// Copyright (c) 2011 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 "chrome/browser/chromeos/status/power_menu_button.h" #include "base/string_number_conversions.h" #include "base/time.h" #include "base/utf_string_conversions.h" #include "chrome/browser/chromeos/cros/cros_library.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/canvas.h" namespace chromeos { //////////////////////////////////////////////////////////////////////////////// // PowerMenuButton // static const int PowerMenuButton::kNumPowerImages = 19; PowerMenuButton::PowerMenuButton(StatusAreaHost* host) : StatusAreaButton(host, this), battery_is_present_(false), line_power_on_(false), battery_fully_charged_(false), battery_percentage_(0.0), icon_id_(-1), ALLOW_THIS_IN_INITIALIZER_LIST(power_menu_(this)) { UpdateIconAndLabelInfo(); CrosLibrary::Get()->GetPowerLibrary()->AddObserver(this); } PowerMenuButton::~PowerMenuButton() { CrosLibrary::Get()->GetPowerLibrary()->RemoveObserver(this); } //////////////////////////////////////////////////////////////////////////////// // PowerMenuButton, ui::MenuModel implementation: int PowerMenuButton::GetItemCount() const { return 2; } ui::MenuModel::ItemType PowerMenuButton::GetTypeAt(int index) const { return ui::MenuModel::TYPE_COMMAND; } string16 PowerMenuButton::GetLabelAt(int index) const { // The first item shows the percentage of battery left. if (index == 0) { return l10n_util::GetStringFUTF16(IDS_STATUSBAR_BATTERY_PERCENTAGE, base::IntToString16(static_cast<int>(battery_percentage_))); } else if (index == 1) { // The second item shows the battery is charged if it is. if (battery_fully_charged_) return l10n_util::GetStringUTF16(IDS_STATUSBAR_BATTERY_IS_CHARGED); // If battery is in an intermediate charge state, show how much time left. base::TimeDelta time = line_power_on_ ? battery_time_to_full_ : battery_time_to_empty_; if (time.InSeconds() == 0) { // If time is 0, then that means we are still calculating how much time. // Depending if line power is on, we either show a message saying that we // are calculating time until full or calculating remaining time. int msg = line_power_on_ ? IDS_STATUSBAR_BATTERY_CALCULATING_TIME_UNTIL_FULL : IDS_STATUSBAR_BATTERY_CALCULATING_TIME_UNTIL_EMPTY; return l10n_util::GetStringUTF16(msg); } else { // Depending if line power is on, we either show a message saying XX:YY // until full or XX:YY remaining where XX is number of hours and YY is // number of minutes. int msg = line_power_on_ ? IDS_STATUSBAR_BATTERY_TIME_UNTIL_FULL : IDS_STATUSBAR_BATTERY_TIME_UNTIL_EMPTY; int hour = time.InHours(); int min = (time - base::TimeDelta::FromHours(hour)).InMinutes(); string16 hour_str = base::IntToString16(hour); string16 min_str = base::IntToString16(min); // Append a "0" before the minute if it's only a single digit. if (min < 10) min_str = ASCIIToUTF16("0") + min_str; return l10n_util::GetStringFUTF16(msg, hour_str, min_str); } } else { NOTREACHED(); return string16(); } } //////////////////////////////////////////////////////////////////////////////// // PowerMenuButton, views::View implementation: void PowerMenuButton::OnLocaleChanged() { UpdateIconAndLabelInfo(); } //////////////////////////////////////////////////////////////////////////////// // PowerMenuButton, views::ViewMenuDelegate implementation: void PowerMenuButton::RunMenu(views::View* source, const gfx::Point& pt) { power_menu_.Rebuild(); power_menu_.RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT); } //////////////////////////////////////////////////////////////////////////////// // PowerMenuButton, PowerLibrary::Observer implementation: void PowerMenuButton::PowerChanged(PowerLibrary* obj) { UpdateIconAndLabelInfo(); } //////////////////////////////////////////////////////////////////////////////// // PowerMenuButton, StatusAreaButton implementation: void PowerMenuButton::UpdateIconAndLabelInfo() { PowerLibrary* cros = CrosLibrary::Get()->GetPowerLibrary(); if (!cros) return; bool cros_loaded = CrosLibrary::Get()->EnsureLoaded(); if (cros_loaded) { battery_is_present_ = cros->battery_is_present(); line_power_on_ = cros->line_power_on(); battery_fully_charged_ = cros->battery_fully_charged(); battery_percentage_ = cros->battery_percentage(); // If fully charged, always show 100% even if internal number is a bit less. // Note: we always call cros->battery_percentage() for test predictability. if (battery_fully_charged_) battery_percentage_ = 100.0; battery_time_to_full_ = cros->battery_time_to_full(); battery_time_to_empty_ = cros->battery_time_to_empty(); } if (!cros_loaded) { icon_id_ = IDR_STATUSBAR_BATTERY_UNKNOWN; } else if (!battery_is_present_) { icon_id_ = IDR_STATUSBAR_BATTERY_MISSING; } else if (line_power_on_ && battery_fully_charged_) { icon_id_ = IDR_STATUSBAR_BATTERY_CHARGED; } else { // Get the power image depending on battery percentage. Percentage is // from 0 to 100, so we need to convert that to 0 to kNumPowerImages - 1. // NOTE: Use an array rather than just calculating a resource number to // avoid creating implicit ordering dependencies on the resource values. static const int kChargingImages[kNumPowerImages] = { IDR_STATUSBAR_BATTERY_CHARGING_1, IDR_STATUSBAR_BATTERY_CHARGING_2, IDR_STATUSBAR_BATTERY_CHARGING_3, IDR_STATUSBAR_BATTERY_CHARGING_4, IDR_STATUSBAR_BATTERY_CHARGING_5, IDR_STATUSBAR_BATTERY_CHARGING_6, IDR_STATUSBAR_BATTERY_CHARGING_7, IDR_STATUSBAR_BATTERY_CHARGING_8, IDR_STATUSBAR_BATTERY_CHARGING_9, IDR_STATUSBAR_BATTERY_CHARGING_10, IDR_STATUSBAR_BATTERY_CHARGING_11, IDR_STATUSBAR_BATTERY_CHARGING_12, IDR_STATUSBAR_BATTERY_CHARGING_13, IDR_STATUSBAR_BATTERY_CHARGING_14, IDR_STATUSBAR_BATTERY_CHARGING_15, IDR_STATUSBAR_BATTERY_CHARGING_16, IDR_STATUSBAR_BATTERY_CHARGING_17, IDR_STATUSBAR_BATTERY_CHARGING_18, IDR_STATUSBAR_BATTERY_CHARGING_19, }; static const int kDischargingImages[kNumPowerImages] = { IDR_STATUSBAR_BATTERY_DISCHARGING_1, IDR_STATUSBAR_BATTERY_DISCHARGING_2, IDR_STATUSBAR_BATTERY_DISCHARGING_3, IDR_STATUSBAR_BATTERY_DISCHARGING_4, IDR_STATUSBAR_BATTERY_DISCHARGING_5, IDR_STATUSBAR_BATTERY_DISCHARGING_6, IDR_STATUSBAR_BATTERY_DISCHARGING_7, IDR_STATUSBAR_BATTERY_DISCHARGING_8, IDR_STATUSBAR_BATTERY_DISCHARGING_9, IDR_STATUSBAR_BATTERY_DISCHARGING_10, IDR_STATUSBAR_BATTERY_DISCHARGING_11, IDR_STATUSBAR_BATTERY_DISCHARGING_12, IDR_STATUSBAR_BATTERY_DISCHARGING_13, IDR_STATUSBAR_BATTERY_DISCHARGING_14, IDR_STATUSBAR_BATTERY_DISCHARGING_15, IDR_STATUSBAR_BATTERY_DISCHARGING_16, IDR_STATUSBAR_BATTERY_DISCHARGING_17, IDR_STATUSBAR_BATTERY_DISCHARGING_18, IDR_STATUSBAR_BATTERY_DISCHARGING_19, }; int index = static_cast<int>(battery_percentage_ / 100.0 * nextafter(static_cast<float>(kNumPowerImages), 0)); index = std::max(std::min(index, kNumPowerImages - 1), 0); icon_id_ = line_power_on_ ? kChargingImages[index] : kDischargingImages[index]; } SetIcon(*ResourceBundle::GetSharedInstance().GetBitmapNamed(icon_id_)); SetTooltipText(UTF16ToWide(GetLabelAt(0))); power_menu_.Rebuild(); SchedulePaint(); } } // namespace chromeos