Home | History | Annotate | Download | only in status
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/status/power_menu_button.h"
      6 
      7 #include "base/string_number_conversions.h"
      8 #include "base/time.h"
      9 #include "base/utf_string_conversions.h"
     10 #include "chrome/browser/chromeos/cros/cros_library.h"
     11 #include "grit/generated_resources.h"
     12 #include "grit/theme_resources.h"
     13 #include "ui/base/l10n/l10n_util.h"
     14 #include "ui/base/resource/resource_bundle.h"
     15 #include "ui/gfx/canvas.h"
     16 
     17 namespace chromeos {
     18 
     19 ////////////////////////////////////////////////////////////////////////////////
     20 // PowerMenuButton
     21 
     22 // static
     23 const int PowerMenuButton::kNumPowerImages = 19;
     24 
     25 PowerMenuButton::PowerMenuButton(StatusAreaHost* host)
     26     : StatusAreaButton(host, this),
     27       battery_is_present_(false),
     28       line_power_on_(false),
     29       battery_fully_charged_(false),
     30       battery_percentage_(0.0),
     31       icon_id_(-1),
     32       ALLOW_THIS_IN_INITIALIZER_LIST(power_menu_(this)) {
     33   UpdateIconAndLabelInfo();
     34   CrosLibrary::Get()->GetPowerLibrary()->AddObserver(this);
     35 }
     36 
     37 PowerMenuButton::~PowerMenuButton() {
     38   CrosLibrary::Get()->GetPowerLibrary()->RemoveObserver(this);
     39 }
     40 
     41 ////////////////////////////////////////////////////////////////////////////////
     42 // PowerMenuButton, ui::MenuModel implementation:
     43 
     44 int PowerMenuButton::GetItemCount() const {
     45   return 2;
     46 }
     47 
     48 ui::MenuModel::ItemType PowerMenuButton::GetTypeAt(int index) const {
     49   return ui::MenuModel::TYPE_COMMAND;
     50 }
     51 
     52 string16 PowerMenuButton::GetLabelAt(int index) const {
     53   // The first item shows the percentage of battery left.
     54   if (index == 0) {
     55     return l10n_util::GetStringFUTF16(IDS_STATUSBAR_BATTERY_PERCENTAGE,
     56         base::IntToString16(static_cast<int>(battery_percentage_)));
     57   } else if (index == 1) {
     58     // The second item shows the battery is charged if it is.
     59     if (battery_fully_charged_)
     60       return l10n_util::GetStringUTF16(IDS_STATUSBAR_BATTERY_IS_CHARGED);
     61 
     62     // If battery is in an intermediate charge state, show how much time left.
     63     base::TimeDelta time = line_power_on_ ? battery_time_to_full_ :
     64         battery_time_to_empty_;
     65     if (time.InSeconds() == 0) {
     66       // If time is 0, then that means we are still calculating how much time.
     67       // Depending if line power is on, we either show a message saying that we
     68       // are calculating time until full or calculating remaining time.
     69       int msg = line_power_on_ ?
     70           IDS_STATUSBAR_BATTERY_CALCULATING_TIME_UNTIL_FULL :
     71           IDS_STATUSBAR_BATTERY_CALCULATING_TIME_UNTIL_EMPTY;
     72       return l10n_util::GetStringUTF16(msg);
     73     } else {
     74       // Depending if line power is on, we either show a message saying XX:YY
     75       // until full or XX:YY remaining where XX is number of hours and YY is
     76       // number of minutes.
     77       int msg = line_power_on_ ? IDS_STATUSBAR_BATTERY_TIME_UNTIL_FULL :
     78           IDS_STATUSBAR_BATTERY_TIME_UNTIL_EMPTY;
     79       int hour = time.InHours();
     80       int min = (time - base::TimeDelta::FromHours(hour)).InMinutes();
     81       string16 hour_str = base::IntToString16(hour);
     82       string16 min_str = base::IntToString16(min);
     83       // Append a "0" before the minute if it's only a single digit.
     84       if (min < 10)
     85         min_str = ASCIIToUTF16("0") + min_str;
     86       return l10n_util::GetStringFUTF16(msg, hour_str, min_str);
     87     }
     88   } else {
     89     NOTREACHED();
     90     return string16();
     91   }
     92 }
     93 
     94 ////////////////////////////////////////////////////////////////////////////////
     95 // PowerMenuButton, views::View implementation:
     96 void PowerMenuButton::OnLocaleChanged() {
     97   UpdateIconAndLabelInfo();
     98 }
     99 
    100 ////////////////////////////////////////////////////////////////////////////////
    101 // PowerMenuButton, views::ViewMenuDelegate implementation:
    102 
    103 void PowerMenuButton::RunMenu(views::View* source, const gfx::Point& pt) {
    104   power_menu_.Rebuild();
    105   power_menu_.RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT);
    106 }
    107 
    108 ////////////////////////////////////////////////////////////////////////////////
    109 // PowerMenuButton, PowerLibrary::Observer implementation:
    110 
    111 void PowerMenuButton::PowerChanged(PowerLibrary* obj) {
    112   UpdateIconAndLabelInfo();
    113 }
    114 
    115 ////////////////////////////////////////////////////////////////////////////////
    116 // PowerMenuButton, StatusAreaButton implementation:
    117 
    118 void PowerMenuButton::UpdateIconAndLabelInfo() {
    119   PowerLibrary* cros = CrosLibrary::Get()->GetPowerLibrary();
    120   if (!cros)
    121     return;
    122 
    123   bool cros_loaded = CrosLibrary::Get()->EnsureLoaded();
    124   if (cros_loaded) {
    125     battery_is_present_ = cros->battery_is_present();
    126     line_power_on_ = cros->line_power_on();
    127     battery_fully_charged_ = cros->battery_fully_charged();
    128     battery_percentage_ = cros->battery_percentage();
    129     // If fully charged, always show 100% even if internal number is a bit less.
    130     // Note: we always call cros->battery_percentage() for test predictability.
    131     if (battery_fully_charged_)
    132       battery_percentage_ = 100.0;
    133     battery_time_to_full_ = cros->battery_time_to_full();
    134     battery_time_to_empty_ = cros->battery_time_to_empty();
    135   }
    136 
    137   if (!cros_loaded) {
    138     icon_id_ = IDR_STATUSBAR_BATTERY_UNKNOWN;
    139   } else if (!battery_is_present_) {
    140     icon_id_ = IDR_STATUSBAR_BATTERY_MISSING;
    141   } else if (line_power_on_ && battery_fully_charged_) {
    142     icon_id_ = IDR_STATUSBAR_BATTERY_CHARGED;
    143   } else {
    144     // Get the power image depending on battery percentage. Percentage is
    145     // from 0 to 100, so we need to convert that to 0 to kNumPowerImages - 1.
    146     // NOTE: Use an array rather than just calculating a resource number to
    147     // avoid creating implicit ordering dependencies on the resource values.
    148     static const int kChargingImages[kNumPowerImages] = {
    149       IDR_STATUSBAR_BATTERY_CHARGING_1,
    150       IDR_STATUSBAR_BATTERY_CHARGING_2,
    151       IDR_STATUSBAR_BATTERY_CHARGING_3,
    152       IDR_STATUSBAR_BATTERY_CHARGING_4,
    153       IDR_STATUSBAR_BATTERY_CHARGING_5,
    154       IDR_STATUSBAR_BATTERY_CHARGING_6,
    155       IDR_STATUSBAR_BATTERY_CHARGING_7,
    156       IDR_STATUSBAR_BATTERY_CHARGING_8,
    157       IDR_STATUSBAR_BATTERY_CHARGING_9,
    158       IDR_STATUSBAR_BATTERY_CHARGING_10,
    159       IDR_STATUSBAR_BATTERY_CHARGING_11,
    160       IDR_STATUSBAR_BATTERY_CHARGING_12,
    161       IDR_STATUSBAR_BATTERY_CHARGING_13,
    162       IDR_STATUSBAR_BATTERY_CHARGING_14,
    163       IDR_STATUSBAR_BATTERY_CHARGING_15,
    164       IDR_STATUSBAR_BATTERY_CHARGING_16,
    165       IDR_STATUSBAR_BATTERY_CHARGING_17,
    166       IDR_STATUSBAR_BATTERY_CHARGING_18,
    167       IDR_STATUSBAR_BATTERY_CHARGING_19,
    168     };
    169     static const int kDischargingImages[kNumPowerImages] = {
    170       IDR_STATUSBAR_BATTERY_DISCHARGING_1,
    171       IDR_STATUSBAR_BATTERY_DISCHARGING_2,
    172       IDR_STATUSBAR_BATTERY_DISCHARGING_3,
    173       IDR_STATUSBAR_BATTERY_DISCHARGING_4,
    174       IDR_STATUSBAR_BATTERY_DISCHARGING_5,
    175       IDR_STATUSBAR_BATTERY_DISCHARGING_6,
    176       IDR_STATUSBAR_BATTERY_DISCHARGING_7,
    177       IDR_STATUSBAR_BATTERY_DISCHARGING_8,
    178       IDR_STATUSBAR_BATTERY_DISCHARGING_9,
    179       IDR_STATUSBAR_BATTERY_DISCHARGING_10,
    180       IDR_STATUSBAR_BATTERY_DISCHARGING_11,
    181       IDR_STATUSBAR_BATTERY_DISCHARGING_12,
    182       IDR_STATUSBAR_BATTERY_DISCHARGING_13,
    183       IDR_STATUSBAR_BATTERY_DISCHARGING_14,
    184       IDR_STATUSBAR_BATTERY_DISCHARGING_15,
    185       IDR_STATUSBAR_BATTERY_DISCHARGING_16,
    186       IDR_STATUSBAR_BATTERY_DISCHARGING_17,
    187       IDR_STATUSBAR_BATTERY_DISCHARGING_18,
    188       IDR_STATUSBAR_BATTERY_DISCHARGING_19,
    189     };
    190 
    191     int index = static_cast<int>(battery_percentage_ / 100.0 *
    192                 nextafter(static_cast<float>(kNumPowerImages), 0));
    193     index = std::max(std::min(index, kNumPowerImages - 1), 0);
    194     icon_id_ = line_power_on_ ?
    195         kChargingImages[index] : kDischargingImages[index];
    196   }
    197 
    198   SetIcon(*ResourceBundle::GetSharedInstance().GetBitmapNamed(icon_id_));
    199   SetTooltipText(UTF16ToWide(GetLabelAt(0)));
    200   power_menu_.Rebuild();
    201   SchedulePaint();
    202 }
    203 
    204 }  // namespace chromeos
    205