diff options
Diffstat (limited to 'chromium/ash/system/chromeos/power/power_status.cc')
-rw-r--r-- | chromium/ash/system/chromeos/power/power_status.cc | 301 |
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 |