[go: nahoru, domu]

blob: 56ae71b95615ba8f3e2a5cd9a821ca3bef89ba30 [file] [log] [blame]
derat@chromium.org349541e2013-06-29 20:56:521// Copyright (c) 2013 The Chromium Authors. All rights reserved.
derat@chromium.org37ce571b2013-06-28 05:28:452// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
James Cooka35a1e22017-04-08 02:33:085#include "ash/system/power/power_status.h"
derat@chromium.org37ce571b2013-06-28 05:28:456
7#include <algorithm>
8#include <cmath>
9
Evan Stade8ff28db2018-05-02 17:15:5710#include "ash/public/cpp/power_utils.h"
estade81c69852016-09-08 21:25:5911#include "ash/resources/vector_icons/vector_icons.h"
jamescooke45f8112017-03-02 16:45:4212#include "ash/strings/grit/ash_strings.h"
Andre Lef08dbd52020-11-02 17:12:0313#include "ash/system/power/battery_image_source.h"
Tetsui Ohkubob264d4d42018-03-12 07:56:1714#include "base/i18n/number_formatting.h"
15#include "base/i18n/time_formatting.h"
derat@chromium.org37ce571b2013-06-28 05:28:4516#include "base/logging.h"
Daniel Cheng23eed1d2017-08-18 02:42:3117#include "base/memory/ptr_util.h"
Peter Kasting8b80a9b2019-09-09 20:27:2318#include "base/numerics/ranges.h"
derat@chromium.org349541e2013-06-29 20:56:5219#include "base/strings/string_number_conversions.h"
20#include "base/strings/utf_string_conversions.h"
Steven Bennetts3330b9f2019-03-15 20:24:1321#include "chromeos/dbus/power/power_manager_client.h"
derat@chromium.org349541e2013-06-29 20:56:5222#include "ui/base/l10n/l10n_util.h"
mukai@chromium.org9d613a92013-08-08 01:07:2923#include "ui/base/l10n/time_format.h"
tdanderson7da397a2016-06-22 19:06:3924#include "ui/display/display.h"
25#include "ui/display/screen.h"
Manu Cornet187c86f2018-12-12 19:29:1626#include "ui/gfx/color_palette.h"
derat@chromium.org349541e2013-06-29 20:56:5227#include "ui/gfx/image/image.h"
derat@chromium.org37ce571b2013-06-28 05:28:4528
29namespace ash {
derat@chromium.org37ce571b2013-06-28 05:28:4530namespace {
31
Evan Stadec2db8572017-06-21 15:08:3232static PowerStatus* g_power_status = nullptr;
33
Jan Wilken Dörrie85285b02021-03-11 23:38:4734std::u16string GetBatteryTimeAccessibilityString(int hour, int min) {
derat@chromium.org349541e2013-06-29 20:56:5235 DCHECK(hour || min);
36 if (hour && !min) {
tnagel@chromium.orgb6cc963b2014-02-27 15:32:2337 return ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION,
38 ui::TimeFormat::LENGTH_LONG,
39 base::TimeDelta::FromHours(hour));
derat@chromium.org349541e2013-06-29 20:56:5240 }
41 if (min && !hour) {
tnagel@chromium.orgb6cc963b2014-02-27 15:32:2342 return ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION,
43 ui::TimeFormat::LENGTH_LONG,
44 base::TimeDelta::FromMinutes(min));
derat@chromium.org349541e2013-06-29 20:56:5245 }
46 return l10n_util::GetStringFUTF16(
47 IDS_ASH_STATUS_TRAY_BATTERY_TIME_ACCESSIBLE,
tnagel@chromium.orgb6cc963b2014-02-27 15:32:2348 ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION,
49 ui::TimeFormat::LENGTH_LONG,
50 base::TimeDelta::FromHours(hour)),
51 ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION,
52 ui::TimeFormat::LENGTH_LONG,
53 base::TimeDelta::FromMinutes(min)));
derat@chromium.org349541e2013-06-29 20:56:5254}
55
michaelpg6ded5ea2015-12-11 18:07:3056int PowerSourceToMessageID(
57 const power_manager::PowerSupplyProperties_PowerSource& source) {
58 switch (source.port()) {
michaelpg69b6f662015-07-27 20:42:0259 case power_manager::PowerSupplyProperties_PowerSource_Port_UNKNOWN:
michaelpg6ded5ea2015-12-11 18:07:3060 return IDS_ASH_POWER_SOURCE_PORT_UNKNOWN;
michaelpg69b6f662015-07-27 20:42:0261 case power_manager::PowerSupplyProperties_PowerSource_Port_LEFT:
michaelpg6ded5ea2015-12-11 18:07:3062 return IDS_ASH_POWER_SOURCE_PORT_LEFT;
michaelpg69b6f662015-07-27 20:42:0263 case power_manager::PowerSupplyProperties_PowerSource_Port_RIGHT:
michaelpg6ded5ea2015-12-11 18:07:3064 return IDS_ASH_POWER_SOURCE_PORT_RIGHT;
michaelpg69b6f662015-07-27 20:42:0265 case power_manager::PowerSupplyProperties_PowerSource_Port_BACK:
michaelpg6ded5ea2015-12-11 18:07:3066 return IDS_ASH_POWER_SOURCE_PORT_BACK;
michaelpg69b6f662015-07-27 20:42:0267 case power_manager::PowerSupplyProperties_PowerSource_Port_FRONT:
michaelpg6ded5ea2015-12-11 18:07:3068 return IDS_ASH_POWER_SOURCE_PORT_FRONT;
michaelpg69b6f662015-07-27 20:42:0269 case power_manager::PowerSupplyProperties_PowerSource_Port_LEFT_FRONT:
michaelpg6ded5ea2015-12-11 18:07:3070 return IDS_ASH_POWER_SOURCE_PORT_LEFT_FRONT;
michaelpg69b6f662015-07-27 20:42:0271 case power_manager::PowerSupplyProperties_PowerSource_Port_LEFT_BACK:
michaelpg6ded5ea2015-12-11 18:07:3072 return IDS_ASH_POWER_SOURCE_PORT_LEFT_BACK;
michaelpg69b6f662015-07-27 20:42:0273 case power_manager::PowerSupplyProperties_PowerSource_Port_RIGHT_FRONT:
michaelpg6ded5ea2015-12-11 18:07:3074 return IDS_ASH_POWER_SOURCE_PORT_RIGHT_FRONT;
michaelpg69b6f662015-07-27 20:42:0275 case power_manager::PowerSupplyProperties_PowerSource_Port_RIGHT_BACK:
michaelpg6ded5ea2015-12-11 18:07:3076 return IDS_ASH_POWER_SOURCE_PORT_RIGHT_BACK;
michaelpg69b6f662015-07-27 20:42:0277 case power_manager::PowerSupplyProperties_PowerSource_Port_BACK_LEFT:
michaelpg6ded5ea2015-12-11 18:07:3078 return IDS_ASH_POWER_SOURCE_PORT_BACK_LEFT;
michaelpg69b6f662015-07-27 20:42:0279 case power_manager::PowerSupplyProperties_PowerSource_Port_BACK_RIGHT:
michaelpg6ded5ea2015-12-11 18:07:3080 return IDS_ASH_POWER_SOURCE_PORT_BACK_RIGHT;
michaelpg69b6f662015-07-27 20:42:0281 }
82 NOTREACHED();
michaelpg6ded5ea2015-12-11 18:07:3083 return 0;
michaelpg69b6f662015-07-27 20:42:0284}
85
derat@chromium.org37ce571b2013-06-28 05:28:4586} // namespace
87
Evan Stadec2db8572017-06-21 15:08:3288bool PowerStatus::BatteryImageInfo::ApproximatelyEqual(
tdanderson7da397a2016-06-22 19:06:3989 const BatteryImageInfo& o) const {
Evan Stadec2db8572017-06-21 15:08:3290 // 100% is distinct from all else.
91 if ((charge_percent != o.charge_percent) &&
92 (charge_percent == 100 || o.charge_percent == 100)) {
93 return false;
94 }
95
96 // Otherwise, consider close values such as 42% and 45% as about the same.
Nico Weberffbc2bd2019-10-02 20:22:5897 return icon_badge == o.icon_badge && alert_if_low == o.alert_if_low &&
Evan Stadec2db8572017-06-21 15:08:3298 std::abs(charge_percent - o.charge_percent) < 5;
tdanderson7da397a2016-06-22 19:06:3999}
100
derat@chromium.orga8b45752013-07-10 06:32:02101const int PowerStatus::kMaxBatteryTimeToDisplaySec = 24 * 60 * 60;
102
estade6d2bd8f2017-03-28 03:16:13103const double PowerStatus::kCriticalBatteryChargePercentage = 5;
tdanderson7da397a2016-06-22 19:06:39104
derat@chromium.org37ce571b2013-06-28 05:28:45105// static
106void PowerStatus::Initialize() {
107 CHECK(!g_power_status);
108 g_power_status = new PowerStatus();
109}
110
111// static
112void PowerStatus::Shutdown() {
113 CHECK(g_power_status);
114 delete g_power_status;
Evan Stadec2db8572017-06-21 15:08:32115 g_power_status = nullptr;
derat@chromium.org37ce571b2013-06-28 05:28:45116}
117
118// static
119bool PowerStatus::IsInitialized() {
Evan Stadec2db8572017-06-21 15:08:32120 return g_power_status != nullptr;
derat@chromium.org37ce571b2013-06-28 05:28:45121}
122
123// static
124PowerStatus* PowerStatus::Get() {
125 CHECK(g_power_status) << "PowerStatus::Get() called before Initialize().";
126 return g_power_status;
127}
128
129void PowerStatus::AddObserver(Observer* observer) {
130 DCHECK(observer);
131 observers_.AddObserver(observer);
132}
133
134void PowerStatus::RemoveObserver(Observer* observer) {
135 DCHECK(observer);
136 observers_.RemoveObserver(observer);
137}
138
derat@chromium.org349541e2013-06-29 20:56:52139void PowerStatus::RequestStatusUpdate() {
Evan Stade523f7fc2019-03-02 19:20:51140 chromeos::PowerManagerClient::Get()->RequestStatusUpdate();
derat@chromium.org349541e2013-06-29 20:56:52141}
142
143bool PowerStatus::IsBatteryPresent() const {
derat@chromium.org9fcb3e22013-07-03 00:35:55144 return proto_.battery_state() !=
jamescookb8dcef522016-06-25 14:42:55145 power_manager::PowerSupplyProperties_BatteryState_NOT_PRESENT;
derat@chromium.org349541e2013-06-29 20:56:52146}
147
148bool PowerStatus::IsBatteryFull() const {
derat@chromium.org9fcb3e22013-07-03 00:35:55149 return proto_.battery_state() ==
jamescookb8dcef522016-06-25 14:42:55150 power_manager::PowerSupplyProperties_BatteryState_FULL;
derat@chromium.org349541e2013-06-29 20:56:52151}
152
derat@chromium.orga8b45752013-07-10 06:32:02153bool PowerStatus::IsBatteryCharging() const {
154 return proto_.battery_state() ==
jamescookb8dcef522016-06-25 14:42:55155 power_manager::PowerSupplyProperties_BatteryState_CHARGING;
derat@chromium.orga8b45752013-07-10 06:32:02156}
157
158bool PowerStatus::IsBatteryDischargingOnLinePower() const {
jamescookb8dcef522016-06-25 14:42:55159 return IsLinePowerConnected() &&
160 proto_.battery_state() ==
161 power_manager::PowerSupplyProperties_BatteryState_DISCHARGING;
derat@chromium.orga8b45752013-07-10 06:32:02162}
163
derat@chromium.org349541e2013-06-29 20:56:52164double PowerStatus::GetBatteryPercent() const {
derat@chromium.org9fcb3e22013-07-03 00:35:55165 return proto_.battery_percent();
derat@chromium.org349541e2013-06-29 20:56:52166}
167
168int PowerStatus::GetRoundedBatteryPercent() const {
Evan Stade8ff28db2018-05-02 17:15:57169 return power_utils::GetRoundedBatteryPercent(GetBatteryPercent());
derat@chromium.org349541e2013-06-29 20:56:52170}
171
172bool PowerStatus::IsBatteryTimeBeingCalculated() const {
derat@chromium.org9fcb3e22013-07-03 00:35:55173 return proto_.is_calculating_battery_time();
derat@chromium.org349541e2013-06-29 20:56:52174}
175
Daniel Erat572a0422019-02-11 22:04:02176base::Optional<base::TimeDelta> PowerStatus::GetBatteryTimeToEmpty() const {
177 // powerd omits the field if no battery is present and sends -1 if it couldn't
178 // compute a reasonable estimate.
179 if (!proto_.has_battery_time_to_empty_sec() ||
180 proto_.battery_time_to_empty_sec() < 0) {
181 return base::nullopt;
182 }
derat@chromium.org9fcb3e22013-07-03 00:35:55183 return base::TimeDelta::FromSeconds(proto_.battery_time_to_empty_sec());
derat@chromium.org349541e2013-06-29 20:56:52184}
185
Daniel Erat572a0422019-02-11 22:04:02186base::Optional<base::TimeDelta> PowerStatus::GetBatteryTimeToFull() const {
187 // powerd omits the field if no battery is present and sends -1 if it couldn't
188 // compute a reasonable estimate.
189 if (!proto_.has_battery_time_to_full_sec() ||
190 proto_.battery_time_to_full_sec() < 0) {
191 return base::nullopt;
192 }
derat@chromium.org9fcb3e22013-07-03 00:35:55193 return base::TimeDelta::FromSeconds(proto_.battery_time_to_full_sec());
derat@chromium.org349541e2013-06-29 20:56:52194}
195
196bool PowerStatus::IsLinePowerConnected() const {
derat@chromium.org9fcb3e22013-07-03 00:35:55197 return proto_.external_power() !=
jamescookb8dcef522016-06-25 14:42:55198 power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED;
derat@chromium.org349541e2013-06-29 20:56:52199}
200
201bool PowerStatus::IsMainsChargerConnected() const {
derat@chromium.org9fcb3e22013-07-03 00:35:55202 return proto_.external_power() ==
jamescookb8dcef522016-06-25 14:42:55203 power_manager::PowerSupplyProperties_ExternalPower_AC;
derat@chromium.org349541e2013-06-29 20:56:52204}
205
206bool PowerStatus::IsUsbChargerConnected() const {
derat@chromium.org9fcb3e22013-07-03 00:35:55207 return proto_.external_power() ==
jamescookb8dcef522016-06-25 14:42:55208 power_manager::PowerSupplyProperties_ExternalPower_USB;
derat@chromium.org349541e2013-06-29 20:56:52209}
210
michaelpg08e65762015-06-13 06:47:40211bool PowerStatus::SupportsDualRoleDevices() const {
212 return proto_.supports_dual_role_devices();
213}
214
michaelpg69b6f662015-07-27 20:42:02215bool PowerStatus::HasDualRoleDevices() const {
216 if (!SupportsDualRoleDevices())
217 return false;
218
219 for (int i = 0; i < proto_.available_external_power_source_size(); i++) {
220 if (!proto_.available_external_power_source(i).active_by_default())
221 return true;
222 }
223 return false;
224}
225
226std::vector<PowerStatus::PowerSource> PowerStatus::GetPowerSources() const {
227 std::vector<PowerSource> sources;
228 for (int i = 0; i < proto_.available_external_power_source_size(); i++) {
229 const auto& source = proto_.available_external_power_source(i);
230 sources.push_back(
231 {source.id(),
232 source.active_by_default() ? DEDICATED_CHARGER : DUAL_ROLE_USB,
michaelpg6ded5ea2015-12-11 18:07:30233 PowerSourceToMessageID(source)});
michaelpg69b6f662015-07-27 20:42:02234 }
235 return sources;
236}
237
238std::string PowerStatus::GetCurrentPowerSourceID() const {
239 return proto_.external_power_source_id();
240}
241
danakjdf0952b2017-04-03 18:38:39242PowerStatus::BatteryImageInfo PowerStatus::GetBatteryImageInfo() const {
derat2eb9055a2016-04-13 00:10:41243 BatteryImageInfo info;
estade6d2bd8f2017-03-28 03:16:13244 CalculateBatteryImageInfo(&info);
tdanderson7da397a2016-06-22 19:06:39245 return info;
246}
derat2eb9055a2016-04-13 00:10:41247
estade6d2bd8f2017-03-28 03:16:13248void PowerStatus::CalculateBatteryImageInfo(BatteryImageInfo* info) const {
Evan Stadec2db8572017-06-21 15:08:32249 info->alert_if_low = !IsLinePowerConnected();
250
tdanderson7da397a2016-06-22 19:06:39251 if (!IsUsbChargerConnected() && !IsBatteryPresent()) {
Tetsui Ohkubod0132522018-10-29 03:08:37252 info->icon_badge = &kUnifiedMenuBatteryXIcon;
Ahmed Mehfooz455697a2020-07-12 05:23:09253 info->badge_outline = &kUnifiedMenuBatteryXOutlineIcon;
Evan Stadec2db8572017-06-21 15:08:32254 info->charge_percent = 0;
tdanderson7da397a2016-06-22 19:06:39255 return;
256 }
257
Ahmed Mehfooz455697a2020-07-12 05:23:09258 if (IsUsbChargerConnected()) {
Tetsui Ohkubod0132522018-10-29 03:08:37259 info->icon_badge = &kUnifiedMenuBatteryUnreliableIcon;
Ahmed Mehfooz455697a2020-07-12 05:23:09260 info->badge_outline = &kUnifiedMenuBatteryUnreliableOutlineIcon;
261 } else if (IsLinePowerConnected()) {
Tetsui Ohkubod0132522018-10-29 03:08:37262 info->icon_badge = &kUnifiedMenuBatteryBoltIcon;
Ahmed Mehfooz455697a2020-07-12 05:23:09263 info->badge_outline = &kUnifiedMenuBatteryBoltOutlineIcon;
264 } else {
estade6d2bd8f2017-03-28 03:16:13265 info->icon_badge = nullptr;
Ahmed Mehfooz455697a2020-07-12 05:23:09266 info->badge_outline = nullptr;
267 }
tdanderson7da397a2016-06-22 19:06:39268
Evan Stadec2db8572017-06-21 15:08:32269 info->charge_percent = GetBatteryPercent();
tdanderson7da397a2016-06-22 19:06:39270
estade6d2bd8f2017-03-28 03:16:13271 // Use an alert badge if the battery is critically low and does not already
tdanderson7da397a2016-06-22 19:06:39272 // have a badge assigned.
estade6d2bd8f2017-03-28 03:16:13273 if (GetBatteryPercent() < kCriticalBatteryChargePercentage &&
274 !info->icon_badge) {
Tetsui Ohkubod0132522018-10-29 03:08:37275 info->icon_badge = &kUnifiedMenuBatteryAlertIcon;
Ahmed Mehfooz455697a2020-07-12 05:23:09276 info->badge_outline = &kUnifiedMenuBatteryAlertOutlineIcon;
derat@chromium.org349541e2013-06-29 20:56:52277 }
derat2eb9055a2016-04-13 00:10:41278}
279
danakjdf0952b2017-04-03 18:38:39280// static
Evan Stadec2db8572017-06-21 15:08:32281gfx::ImageSkia PowerStatus::GetBatteryImage(const BatteryImageInfo& info,
282 int height,
283 SkColor bg_color,
284 SkColor fg_color) {
285 auto* source = new BatteryImageSource(info, height, bg_color, fg_color);
Daniel Cheng23eed1d2017-08-18 02:42:31286 return gfx::ImageSkia(base::WrapUnique(source), source->size());
tdanderson7da397a2016-06-22 19:06:39287}
288
Jan Wilken Dörrie85285b02021-03-11 23:38:47289std::u16string PowerStatus::GetAccessibleNameString(
evy@chromium.org04c3b4582014-07-23 00:09:24290 bool full_description) const {
derat@chromium.orga8b45752013-07-10 06:32:02291 if (IsBatteryFull()) {
estade6d2bd8f2017-03-28 03:16:13292 return l10n_util::GetStringUTF16(
derat@chromium.org349541e2013-06-29 20:56:52293 IDS_ASH_STATUS_TRAY_BATTERY_FULL_CHARGE_ACCESSIBLE);
294 }
derat@chromium.orga8b45752013-07-10 06:32:02295
Jan Wilken Dörrie85285b02021-03-11 23:38:47296 std::u16string battery_percentage_accessible = l10n_util::GetStringFUTF16(
jamescookb8dcef522016-06-25 14:42:55297 IsBatteryCharging()
298 ? IDS_ASH_STATUS_TRAY_BATTERY_PERCENT_CHARGING_ACCESSIBLE
299 : IDS_ASH_STATUS_TRAY_BATTERY_PERCENT_ACCESSIBLE,
Raul Tambre73f906942019-02-11 16:47:21300 base::NumberToString16(GetRoundedBatteryPercent()));
evy@chromium.org04c3b4582014-07-23 00:09:24301 if (!full_description)
302 return battery_percentage_accessible;
303
Jan Wilken Dörrie85285b02021-03-11 23:38:47304 std::u16string battery_time_accessible = std::u16string();
Daniel Erat572a0422019-02-11 22:04:02305 const base::Optional<base::TimeDelta> time =
jamescookb8dcef522016-06-25 14:42:55306 IsBatteryCharging() ? GetBatteryTimeToFull() : GetBatteryTimeToEmpty();
derat@chromium.orga8b45752013-07-10 06:32:02307
derat@chromium.org349541e2013-06-29 20:56:52308 if (IsUsbChargerConnected()) {
estade6d2bd8f2017-03-28 03:16:13309 battery_time_accessible = l10n_util::GetStringUTF16(
derat@chromium.org349541e2013-06-29 20:56:52310 IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE_ACCESSIBLE);
derat@chromium.orga8b45752013-07-10 06:32:02311 } else if (IsBatteryTimeBeingCalculated()) {
estade6d2bd8f2017-03-28 03:16:13312 battery_time_accessible = l10n_util::GetStringUTF16(
derat@chromium.orga8b45752013-07-10 06:32:02313 IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING_ACCESSIBLE);
Daniel Erat572a0422019-02-11 22:04:02314 } else if (time && power_utils::ShouldDisplayBatteryTime(*time) &&
derat@chromium.orga8b45752013-07-10 06:32:02315 !IsBatteryDischargingOnLinePower()) {
316 int hour = 0, min = 0;
Daniel Erat572a0422019-02-11 22:04:02317 power_utils::SplitTimeIntoHoursAndMinutes(*time, &hour, &min);
Jan Wilken Dörrie85285b02021-03-11 23:38:47318 std::u16string minute =
Raul Tambre73f906942019-02-11 16:47:21319 min < 10 ? base::ASCIIToUTF16("0") + base::NumberToString16(min)
320 : base::NumberToString16(min);
jamescookb8dcef522016-06-25 14:42:55321 battery_time_accessible = l10n_util::GetStringFUTF16(
322 IsBatteryCharging()
323 ? IDS_ASH_STATUS_TRAY_BATTERY_TIME_UNTIL_FULL_ACCESSIBLE
324 : IDS_ASH_STATUS_TRAY_BATTERY_TIME_LEFT_ACCESSIBLE,
325 GetBatteryTimeAccessibilityString(hour, min));
derat@chromium.org349541e2013-06-29 20:56:52326 }
jamescookb8dcef522016-06-25 14:42:55327 return battery_time_accessible.empty()
328 ? battery_percentage_accessible
Sammie Quoncf5561e2017-09-27 23:22:13329 : battery_percentage_accessible + base::ASCIIToUTF16(" ") +
jamescookb8dcef522016-06-25 14:42:55330 battery_time_accessible;
derat@chromium.org349541e2013-06-29 20:56:52331}
332
Jan Wilken Dörrie85285b02021-03-11 23:38:47333std::pair<std::u16string, std::u16string> PowerStatus::GetStatusStrings()
Tetsui Ohkubob264d4d42018-03-12 07:56:17334 const {
Jan Wilken Dörrie85285b02021-03-11 23:38:47335 std::u16string percentage;
336 std::u16string status;
Tetsui Ohkubob264d4d42018-03-12 07:56:17337 if (IsBatteryFull()) {
338 status = l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_FULL);
339 } else {
340 percentage = base::FormatPercent(GetRoundedBatteryPercent());
341 if (IsUsbChargerConnected()) {
342 status = l10n_util::GetStringUTF16(
343 IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE);
344 } else if (IsBatteryTimeBeingCalculated()) {
345 status =
346 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING);
347 } else {
Daniel Erat572a0422019-02-11 22:04:02348 base::Optional<base::TimeDelta> time = IsBatteryCharging()
349 ? GetBatteryTimeToFull()
Tetsui Ohkubob264d4d42018-03-12 07:56:17350 : GetBatteryTimeToEmpty();
Daniel Erat572a0422019-02-11 22:04:02351 if (time && power_utils::ShouldDisplayBatteryTime(*time) &&
Tetsui Ohkubob264d4d42018-03-12 07:56:17352 !IsBatteryDischargingOnLinePower()) {
Jan Wilken Dörrie85285b02021-03-11 23:38:47353 std::u16string duration;
Daniel Erat572a0422019-02-11 22:04:02354 if (!base::TimeDurationFormat(*time, base::DURATION_WIDTH_NUMERIC,
Tetsui Ohkubob264d4d42018-03-12 07:56:17355 &duration))
Daniel Erat572a0422019-02-11 22:04:02356 LOG(ERROR) << "Failed to format duration " << *time;
Tetsui Ohkubob264d4d42018-03-12 07:56:17357 status = l10n_util::GetStringFUTF16(
358 IsBatteryCharging()
359 ? IDS_ASH_STATUS_TRAY_BATTERY_TIME_UNTIL_FULL_SHORT
360 : IDS_ASH_STATUS_TRAY_BATTERY_TIME_LEFT_SHORT,
361 duration);
362 }
363 }
364 }
365
366 return std::make_pair(percentage, status);
367}
368
Jan Wilken Dörrie85285b02021-03-11 23:38:47369std::u16string PowerStatus::GetInlinedStatusString() const {
370 std::u16string percentage_text;
371 std::u16string status_text;
Tatsuhisa Yamaguchibb76e2f2018-10-31 06:41:34372 std::tie(percentage_text, status_text) = GetStatusStrings();
373
374 if (!percentage_text.empty() && !status_text.empty()) {
375 return percentage_text +
376 l10n_util::GetStringUTF16(
377 IDS_ASH_STATUS_TRAY_BATTERY_STATUS_SEPARATOR) +
378 status_text;
379 } else if (!percentage_text.empty()) {
380 return percentage_text;
381 } else {
382 return status_text;
383 }
384}
385
Sam McNally366a21942020-09-18 04:02:53386double PowerStatus::GetPreferredMinimumPower() const {
Sam McNally9d5a10f2020-09-25 04:09:28387 return proto_.preferred_minimum_external_power();
Sam McNally366a21942020-09-18 04:02:53388}
389
derat@chromium.org37ce571b2013-06-28 05:28:45390PowerStatus::PowerStatus() {
Evan Stade523f7fc2019-03-02 19:20:51391 chromeos::PowerManagerClient::Get()->AddObserver(this);
392 chromeos::PowerManagerClient::Get()->RequestStatusUpdate();
derat@chromium.org37ce571b2013-06-28 05:28:45393}
394
395PowerStatus::~PowerStatus() {
Evan Stade523f7fc2019-03-02 19:20:51396 chromeos::PowerManagerClient::Get()->RemoveObserver(this);
derat@chromium.org37ce571b2013-06-28 05:28:45397}
398
derat@chromium.org9fcb3e22013-07-03 00:35:55399void PowerStatus::SetProtoForTesting(
400 const power_manager::PowerSupplyProperties& proto) {
401 proto_ = proto;
derat@chromium.org9fcb3e22013-07-03 00:35:55402}
derat@chromium.org37ce571b2013-06-28 05:28:45403
derat@chromium.org9fcb3e22013-07-03 00:35:55404void PowerStatus::PowerChanged(
405 const power_manager::PowerSupplyProperties& proto) {
406 proto_ = proto;
ericwilligers5c579312016-10-14 20:07:33407 for (auto& observer : observers_)
408 observer.OnPowerStatusChanged();
derat@chromium.org37ce571b2013-06-28 05:28:45409}
410
derat@chromium.org37ce571b2013-06-28 05:28:45411} // namespace ash