summaryrefslogtreecommitdiff
path: root/chromium/ash/system/chromeos/power/power_status.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ash/system/chromeos/power/power_status.cc')
-rw-r--r--chromium/ash/system/chromeos/power/power_status.cc301
1 files changed, 301 insertions, 0 deletions
diff --git a/chromium/ash/system/chromeos/power/power_status.cc b/chromium/ash/system/chromeos/power/power_status.cc
new file mode 100644
index 00000000000..b4b5d94ccf4
--- /dev/null
+++ b/chromium/ash/system/chromeos/power/power_status.cc
@@ -0,0 +1,301 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/chromeos/power/power_status.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "ash/shell.h"
+#include "ash/shell_delegate.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/power_manager_client.h"
+#include "grit/ash_resources.h"
+#include "grit/ash_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/time_format.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_skia_operations.h"
+#include "ui/gfx/rect.h"
+
+namespace ash {
+namespace internal {
+
+namespace {
+
+// Updates |proto| to ensure that its fields are consistent.
+void SanitizeProto(power_manager::PowerSupplyProperties* proto) {
+ DCHECK(proto);
+
+ if (proto->battery_state() ==
+ power_manager::PowerSupplyProperties_BatteryState_FULL)
+ proto->set_battery_percent(100.0);
+
+ if (!proto->is_calculating_battery_time()) {
+ const bool on_line_power = proto->external_power() !=
+ power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED;
+ if ((on_line_power && proto->battery_time_to_full_sec() < 0) ||
+ (!on_line_power && proto->battery_time_to_empty_sec() < 0))
+ proto->set_is_calculating_battery_time(true);
+ }
+}
+
+base::string16 GetBatteryTimeAccessibilityString(int hour, int min) {
+ DCHECK(hour || min);
+ if (hour && !min) {
+ return ui::TimeFormat::TimeDurationLong(base::TimeDelta::FromHours(hour));
+ }
+ if (min && !hour) {
+ return ui::TimeFormat::TimeDurationLong(base::TimeDelta::FromMinutes(min));
+ }
+ return l10n_util::GetStringFUTF16(
+ IDS_ASH_STATUS_TRAY_BATTERY_TIME_ACCESSIBLE,
+ ui::TimeFormat::TimeDurationLong(base::TimeDelta::FromHours(hour)),
+ ui::TimeFormat::TimeDurationLong(base::TimeDelta::FromMinutes(min)));
+}
+
+static PowerStatus* g_power_status = NULL;
+
+// Minimum battery percentage rendered in UI.
+const int kMinBatteryPercent = 1;
+
+// Width and height of battery images.
+const int kBatteryImageHeight = 25;
+const int kBatteryImageWidth = 25;
+
+// Number of different power states.
+const int kNumPowerImages = 15;
+
+} // namespace
+
+const int PowerStatus::kMaxBatteryTimeToDisplaySec = 24 * 60 * 60;
+
+// static
+void PowerStatus::Initialize() {
+ CHECK(!g_power_status);
+ g_power_status = new PowerStatus();
+}
+
+// static
+void PowerStatus::Shutdown() {
+ CHECK(g_power_status);
+ delete g_power_status;
+ g_power_status = NULL;
+}
+
+// static
+bool PowerStatus::IsInitialized() {
+ return g_power_status != NULL;
+}
+
+// static
+PowerStatus* PowerStatus::Get() {
+ CHECK(g_power_status) << "PowerStatus::Get() called before Initialize().";
+ return g_power_status;
+}
+
+// static
+bool PowerStatus::ShouldDisplayBatteryTime(const base::TimeDelta& time) {
+ return time >= base::TimeDelta::FromMinutes(1) &&
+ time.InSeconds() <= kMaxBatteryTimeToDisplaySec;
+}
+
+// static
+void PowerStatus::SplitTimeIntoHoursAndMinutes(const base::TimeDelta& time,
+ int* hours,
+ int* minutes) {
+ DCHECK(hours);
+ DCHECK(minutes);
+ *hours = time.InHours();
+ const double seconds =
+ (time - base::TimeDelta::FromHours(*hours)).InSecondsF();
+ *minutes = static_cast<int>(seconds / 60.0 + 0.5);
+}
+
+void PowerStatus::AddObserver(Observer* observer) {
+ DCHECK(observer);
+ observers_.AddObserver(observer);
+}
+
+void PowerStatus::RemoveObserver(Observer* observer) {
+ DCHECK(observer);
+ observers_.RemoveObserver(observer);
+}
+
+void PowerStatus::RequestStatusUpdate() {
+ chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
+ RequestStatusUpdate();
+}
+
+bool PowerStatus::IsBatteryPresent() const {
+ return proto_.battery_state() !=
+ power_manager::PowerSupplyProperties_BatteryState_NOT_PRESENT;
+}
+
+bool PowerStatus::IsBatteryFull() const {
+ return proto_.battery_state() ==
+ power_manager::PowerSupplyProperties_BatteryState_FULL;
+}
+
+bool PowerStatus::IsBatteryCharging() const {
+ return proto_.battery_state() ==
+ power_manager::PowerSupplyProperties_BatteryState_CHARGING;
+}
+
+bool PowerStatus::IsBatteryDischargingOnLinePower() const {
+ return IsLinePowerConnected() && proto_.battery_state() ==
+ power_manager::PowerSupplyProperties_BatteryState_DISCHARGING;
+}
+
+double PowerStatus::GetBatteryPercent() const {
+ return proto_.battery_percent();
+}
+
+int PowerStatus::GetRoundedBatteryPercent() const {
+ return std::max(kMinBatteryPercent,
+ static_cast<int>(GetBatteryPercent() + 0.5));
+}
+
+bool PowerStatus::IsBatteryTimeBeingCalculated() const {
+ return proto_.is_calculating_battery_time();
+}
+
+base::TimeDelta PowerStatus::GetBatteryTimeToEmpty() const {
+ return base::TimeDelta::FromSeconds(proto_.battery_time_to_empty_sec());
+}
+
+base::TimeDelta PowerStatus::GetBatteryTimeToFull() const {
+ return base::TimeDelta::FromSeconds(proto_.battery_time_to_full_sec());
+}
+
+bool PowerStatus::IsLinePowerConnected() const {
+ return proto_.external_power() !=
+ power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED;
+}
+
+bool PowerStatus::IsMainsChargerConnected() const {
+ return proto_.external_power() ==
+ power_manager::PowerSupplyProperties_ExternalPower_AC;
+}
+
+bool PowerStatus::IsUsbChargerConnected() const {
+ return proto_.external_power() ==
+ power_manager::PowerSupplyProperties_ExternalPower_USB;
+}
+
+bool PowerStatus::IsOriginalSpringChargerConnected() const {
+ return proto_.external_power() == power_manager::
+ PowerSupplyProperties_ExternalPower_ORIGINAL_SPRING_CHARGER;
+}
+
+gfx::ImageSkia PowerStatus::GetBatteryImage(IconSet icon_set) const {
+ gfx::Image all;
+ if (IsUsbChargerConnected()) {
+ all = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+ icon_set == ICON_DARK ?
+ IDR_AURA_UBER_TRAY_POWER_SMALL_CHARGING_UNRELIABLE_DARK :
+ IDR_AURA_UBER_TRAY_POWER_SMALL_CHARGING_UNRELIABLE);
+ } else {
+ all = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+ icon_set == ICON_DARK ?
+ IDR_AURA_UBER_TRAY_POWER_SMALL_DARK : IDR_AURA_UBER_TRAY_POWER_SMALL);
+ }
+
+ // Get the horizontal offset in the battery icon array image. The USB /
+ // "unreliable charging" image has a single column of icons; the other
+ // image contains a "battery" column on the left and a "line power"
+ // column on the right.
+ int offset = IsUsbChargerConnected() ? 0 : (IsLinePowerConnected() ? 1 : 0);
+
+ // Get the vertical offset corresponding to the current battery level.
+ int index = -1;
+ if (GetBatteryPercent() >= 100.0) {
+ index = kNumPowerImages - 1;
+ } else if (!IsBatteryPresent()) {
+ index = kNumPowerImages;
+ } else {
+ index = static_cast<int>(
+ GetBatteryPercent() / 100.0 * (kNumPowerImages - 1));
+ index = std::max(std::min(index, kNumPowerImages - 2), 0);
+ }
+
+ gfx::Rect region(
+ offset * kBatteryImageWidth, index * kBatteryImageHeight,
+ kBatteryImageWidth, kBatteryImageHeight);
+ return gfx::ImageSkiaOperations::ExtractSubset(*all.ToImageSkia(), region);
+}
+
+base::string16 PowerStatus::GetAccessibleNameString() const {
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ if (IsBatteryFull()) {
+ return rb.GetLocalizedString(
+ IDS_ASH_STATUS_TRAY_BATTERY_FULL_CHARGE_ACCESSIBLE);
+ }
+
+ base::string16 battery_percentage_accessible = l10n_util::GetStringFUTF16(
+ IsBatteryCharging() ?
+ IDS_ASH_STATUS_TRAY_BATTERY_PERCENT_CHARGING_ACCESSIBLE :
+ IDS_ASH_STATUS_TRAY_BATTERY_PERCENT_ACCESSIBLE,
+ base::IntToString16(GetRoundedBatteryPercent()));
+ base::string16 battery_time_accessible = base::string16();
+ const base::TimeDelta time = IsBatteryCharging() ? GetBatteryTimeToFull() :
+ GetBatteryTimeToEmpty();
+
+ if (IsUsbChargerConnected()) {
+ battery_time_accessible = rb.GetLocalizedString(
+ IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE_ACCESSIBLE);
+ } else if (IsBatteryTimeBeingCalculated()) {
+ battery_time_accessible = rb.GetLocalizedString(
+ IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING_ACCESSIBLE);
+ } else if (ShouldDisplayBatteryTime(time) &&
+ !IsBatteryDischargingOnLinePower()) {
+ int hour = 0, min = 0;
+ PowerStatus::SplitTimeIntoHoursAndMinutes(time, &hour, &min);
+ base::string16 minute = min < 10 ?
+ ASCIIToUTF16("0") + base::IntToString16(min) :
+ base::IntToString16(min);
+ battery_time_accessible =
+ l10n_util::GetStringFUTF16(
+ IsBatteryCharging() ?
+ IDS_ASH_STATUS_TRAY_BATTERY_TIME_UNTIL_FULL_ACCESSIBLE :
+ IDS_ASH_STATUS_TRAY_BATTERY_TIME_LEFT_ACCESSIBLE,
+ GetBatteryTimeAccessibilityString(hour, min));
+ }
+ return battery_time_accessible.empty() ?
+ battery_percentage_accessible :
+ battery_percentage_accessible + ASCIIToUTF16(". ") +
+ battery_time_accessible;
+}
+
+PowerStatus::PowerStatus() {
+ chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
+ AddObserver(this);
+ chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
+ RequestStatusUpdate();
+}
+
+PowerStatus::~PowerStatus() {
+ chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
+ RemoveObserver(this);
+}
+
+void PowerStatus::SetProtoForTesting(
+ const power_manager::PowerSupplyProperties& proto) {
+ proto_ = proto;
+ SanitizeProto(&proto_);
+}
+
+void PowerStatus::PowerChanged(
+ const power_manager::PowerSupplyProperties& proto) {
+ proto_ = proto;
+ SanitizeProto(&proto_);
+ FOR_EACH_OBSERVER(Observer, observers_, OnPowerStatusChanged());
+}
+
+} // namespace internal
+} // namespace ash