summaryrefslogtreecommitdiffstats
path: root/ash/system
diff options
context:
space:
mode:
Diffstat (limited to 'ash/system')
-rw-r--r--ash/system/power/tray_power.cc313
-rw-r--r--ash/system/power/tray_power.h17
-rw-r--r--ash/system/tray/tray_views.cc50
-rw-r--r--ash/system/tray/tray_views.h24
4 files changed, 338 insertions, 66 deletions
diff --git a/ash/system/power/tray_power.cc b/ash/system/power/tray_power.cc
index 361bd93..95f6f8d 100644
--- a/ash/system/power/tray_power.cc
+++ b/ash/system/power/tray_power.cc
@@ -4,12 +4,14 @@
#include "ash/system/power/tray_power.h"
+#include "ash/ash_switches.h"
#include "ash/shell.h"
#include "ash/system/date/date_view.h"
#include "ash/system/power/power_supply_status.h"
#include "ash/system/tray/system_tray_delegate.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/system/tray/tray_views.h"
+#include "base/command_line.h"
#include "base/string_number_conversions.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
@@ -27,6 +29,7 @@
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
+#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "unicode/fieldpos.h"
@@ -43,8 +46,49 @@ const int kBatteryImageWidth = 25;
const int kNumPowerImages = 15;
// Top/bottom padding of the text items.
const int kPaddingVertical = 10;
+// Specify min width of status label for layout.
+const int kLabelMinWidth = 120;
+// Notification times.
+const int kCriticalSeconds = 5 * 60;
+const int kLowPowerSeconds = 15 * 60;
+const int kNoWarningSeconds = 30 * 60;
+
+enum IconSet {
+ ICON_LIGHT,
+ ICON_DARK
+};
+
+SkBitmap GetBatteryImage(const PowerSupplyStatus& supply_status,
+ IconSet icon_set) {
+ SkBitmap image;
+ gfx::Image all = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+ icon_set == ICON_DARK ?
+ IDR_AURA_UBER_TRAY_POWER_SMALL_DARK : IDR_AURA_UBER_TRAY_POWER_SMALL);
+
+ int image_index = 0;
+ if (supply_status.battery_percentage >= 100) {
+ image_index = kNumPowerImages - 1;
+ } else if (!supply_status.battery_is_present) {
+ image_index = kNumPowerImages;
+ } else {
+ double percentage = supply_status.is_calculating_battery_time ? 100.0 :
+ supply_status.battery_percentage;
+ image_index = static_cast<int>(percentage / 100.0 * (kNumPowerImages - 1));
+ image_index = std::max(std::min(image_index, kNumPowerImages - 2), 0);
+ }
+
+ // TODO(mbolohan): Remove the 2px offset when the assets are centered. See
+ // crbug.com/119832.
+ SkIRect region = SkIRect::MakeXYWH(
+ (supply_status.line_power_on ? kBatteryImageWidth : 0) + 2,
+ image_index * kBatteryImageHeight,
+ kBatteryImageWidth - 2, kBatteryImageHeight);
+ all.ToSkBitmap()->extractSubset(&image, region);
+ return image;
}
+} // namespace
+
namespace tray {
// This view is used only for the tray.
@@ -69,32 +113,7 @@ class PowerTrayView : public views::ImageView {
private:
void UpdateImage() {
- SkBitmap image;
- gfx::Image all = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
- IDR_AURA_UBER_TRAY_POWER_SMALL);
-
- int image_index = 0;
- if (supply_status_.battery_percentage >= 100) {
- image_index = kNumPowerImages - 1;
- } else if (!supply_status_.battery_is_present) {
- image_index = kNumPowerImages;
- } else {
- image_index = static_cast<int> (
- supply_status_.battery_percentage / 100.0 *
- (kNumPowerImages - 1));
- image_index =
- std::max(std::min(image_index, kNumPowerImages - 2), 0);
- }
-
- // TODO(mbolohan): Remove the 2px offset when the assets are centered. See
- // crbug.com/119832.
- SkIRect region = SkIRect::MakeXYWH(
- (supply_status_.line_power_on ? kBatteryImageWidth : 0) + 2,
- image_index * kBatteryImageHeight,
- kBatteryImageWidth - 2, kBatteryImageHeight);
- all.ToSkBitmap()->extractSubset(&image, region);
-
- SetImage(image);
+ SetImage(GetBatteryImage(supply_status_, ICON_LIGHT));
}
PowerSupplyStatus supply_status_;
@@ -103,23 +122,38 @@ class PowerTrayView : public views::ImageView {
};
// This view is used only for the popup.
-class PowerPopupView : public views::View {
+class PowerStatusView : public views::View {
public:
- PowerPopupView() {
+ enum ViewType {
+ VIEW_DEFAULT,
+ VIEW_NOTIFICATION
+ };
+
+ explicit PowerStatusView(ViewType view_type) {
status_label_ = new views::Label;
status_label_->SetHorizontalAlignment(views::Label::ALIGN_RIGHT);
time_label_ = new views::Label;
time_label_->SetHorizontalAlignment(views::Label::ALIGN_RIGHT);
- UpdateText();
- SetLayoutManager(
- new views::BoxLayout(
- views::BoxLayout::kVertical, 0, 0, kTrayPopupTextSpacingVertical));
+ icon_ = new views::ImageView;
+
AddChildView(status_label_);
AddChildView(time_label_);
+ AddChildView(icon_);
+
+ if (view_type == VIEW_DEFAULT)
+ LayoutDefaultView();
+ else
+ LayoutNotificationView();
+
+ Update();
+
+ set_border(views::Border::CreateEmptyBorder(
+ kPaddingVertical, kTrayPopupPaddingHorizontal,
+ kPaddingVertical, kTrayPopupPaddingHorizontal));
}
- virtual ~PowerPopupView() {
+ virtual ~PowerStatusView() {
}
void UpdatePowerStatus(const PowerSupplyStatus& status) {
@@ -128,69 +162,162 @@ class PowerPopupView : public views::View {
if (supply_status_.battery_is_full)
supply_status_.battery_percentage = 100.0;
- UpdateText();
+ Update();
}
private:
- void UpdateText() {
- if (supply_status_.is_calculating_battery_time) {
- status_label_->SetText(
- l10n_util::GetStringFUTF16(
- IDS_ASH_STATUS_TRAY_BATTERY_PERCENT,
- base::IntToString16(
- static_cast<int>(supply_status_.battery_percentage))));
- time_label_->SetText(
- ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
- supply_status_.line_power_on ?
- IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING_ON :
- IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING_OFF));
- return;
- }
+ void LayoutDefaultView() {
+ views::GridLayout* layout = new views::GridLayout(this);
+ SetLayoutManager(layout);
+
+ views::ColumnSet* columns = layout->AddColumnSet(0);
+
+ columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal);
+ // Status + Time
+ columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
+ 0, views::GridLayout::USE_PREF, 0, kLabelMinWidth);
+
+ columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal/2);
+
+ // Icon
+ columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
+ 0, views::GridLayout::USE_PREF, 0, 0);
+
+ columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal);
+
+ layout->AddPaddingRow(0, kPaddingVertical);
+
+ layout->StartRow(0, 0);
+ layout->AddView(status_label_);
+ layout->AddView(icon_, 1, 3); // 3 rows for icon
+
+ layout->AddPaddingRow(0, kPaddingVertical/3);
+ layout->StartRow(0, 0);
+ layout->AddView(time_label_);
+ layout->AddPaddingRow(0, kPaddingVertical);
+ }
+
+ void LayoutNotificationView() {
+ views::GridLayout* layout = new views::GridLayout(this);
+ SetLayoutManager(layout);
+
+ views::ColumnSet* columns = layout->AddColumnSet(0);
+
+ // Icon
+ columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
+ 0, views::GridLayout::USE_PREF, 0, 0);
+
+ columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal/2);
+
+ // Status + Time
+ columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
+ 0, views::GridLayout::USE_PREF, 0, kLabelMinWidth);
+
+ layout->AddPaddingRow(0, kPaddingVertical);
+
+ layout->StartRow(0, 0);
+ layout->AddView(icon_, 1, 3); // 3 rows for icon
+ layout->AddView(status_label_);
+ layout->AddPaddingRow(0, kPaddingVertical/3);
+
+ layout->StartRow(0, 0);
+ layout->SkipColumns(1);
+ layout->AddView(time_label_);
+
+ layout->AddPaddingRow(0, kPaddingVertical);
+ }
+
+ void UpdateText() {
base::TimeDelta time = base::TimeDelta::FromSeconds(
supply_status_.line_power_on ?
supply_status_.averaged_battery_time_to_full :
supply_status_.averaged_battery_time_to_empty);
int hour = time.InHours();
int min = (time - base::TimeDelta::FromHours(hour)).InMinutes();
- if (hour || min) {
+
+ if (supply_status_.line_power_on && !hour && !min) {
+ status_label_->SetText(
+ ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
+ IDS_ASH_STATUS_TRAY_BATTERY_FULL));
+ } else {
status_label_->SetText(
l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_BATTERY_PERCENT,
base::IntToString16(
static_cast<int>(supply_status_.battery_percentage))));
+ }
+
+ if (supply_status_.is_calculating_battery_time) {
+ time_label_->SetText(
+ ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
+ IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING));
+ } else if (hour || min) {
time_label_->SetText(
l10n_util::GetStringFUTF16(
supply_status_.line_power_on ?
- IDS_ASH_STATUS_TRAY_BATTERY_TIME_UNTIL_FULL :
- IDS_ASH_STATUS_TRAY_BATTERY_TIME_UNTIL_EMPTY,
+ IDS_ASH_STATUS_TRAY_BATTERY_TIME_UNTIL_FULL :
+ IDS_ASH_STATUS_TRAY_BATTERY_TIME_UNTIL_EMPTY,
base::IntToString16(hour),
base::IntToString16(min)));
} else {
- if (supply_status_.line_power_on) {
- status_label_->SetText(
- ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
- IDS_ASH_STATUS_TRAY_BATTERY_FULL));
- } else {
- // Completely discharged? ... ha?
- status_label_->SetText(string16());
- }
time_label_->SetText(string16());
}
}
+ void UpdateIcon() {
+ icon_->SetImage(GetBatteryImage(supply_status_, ICON_DARK));
+ icon_->SetVisible(true);
+ }
+
+ void Update() {
+ UpdateText();
+ UpdateIcon();
+ }
+
views::Label* status_label_;
views::Label* time_label_;
+ views::ImageView* icon_;
PowerSupplyStatus supply_status_;
- DISALLOW_COPY_AND_ASSIGN(PowerPopupView);
+ DISALLOW_COPY_AND_ASSIGN(PowerStatusView);
+};
+
+class PowerNotificationView : public TrayNotificationView {
+ public:
+ explicit PowerNotificationView(TrayPower* tray)
+ : tray_(tray) {
+ power_status_view_ =
+ new PowerStatusView(PowerStatusView::VIEW_NOTIFICATION);
+ InitView(power_status_view_);
+ }
+
+ void UpdatePowerStatus(const PowerSupplyStatus& status) {
+ power_status_view_->UpdatePowerStatus(status);
+ }
+
+ // Overridden from TrayNotificationView:
+ virtual void OnClose() OVERRIDE {
+ tray_->HideNotificationView();
+ }
+
+ private:
+ TrayPower* tray_;
+ tray::PowerStatusView* power_status_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(PowerNotificationView);
};
} // namespace tray
+using tray::PowerStatusView;
+using tray::PowerNotificationView;
+
TrayPower::TrayPower()
- : power_tray_(NULL) {
+ : power_tray_(NULL),
+ notification_view_(NULL),
+ notification_state_(NOTIFICATION_NONE) {
}
TrayPower::~TrayPower() {
@@ -209,11 +336,22 @@ views::View* TrayPower::CreateTrayView(user::LoginStatus status) {
}
views::View* TrayPower::CreateDefaultView(user::LoginStatus status) {
+ // Make sure icon status is up-to-date. (Also triggers stub activation).
+ ash::Shell::GetInstance()->tray_delegate()->RequestStatusUpdate();
return NULL;
}
-views::View* TrayPower::CreateDetailedView(user::LoginStatus status) {
- return NULL;
+views::View* TrayPower::CreateNotificationView(user::LoginStatus status) {
+ CHECK(notification_view_ == NULL);
+ PowerSupplyStatus power_status =
+ ash::Shell::GetInstance()->tray_delegate()->GetPowerSupplyStatus();
+ if (!power_status.battery_is_present)
+ return NULL;
+
+ notification_view_ = new PowerNotificationView(this);
+ notification_view_->UpdatePowerStatus(power_status);
+
+ return notification_view_;
}
void TrayPower::DestroyTrayView() {
@@ -223,7 +361,8 @@ void TrayPower::DestroyTrayView() {
void TrayPower::DestroyDefaultView() {
}
-void TrayPower::DestroyDetailedView() {
+void TrayPower::DestroyNotificationView() {
+ notification_view_ = NULL;
}
void TrayPower::UpdateAfterLoginStatusChange(user::LoginStatus status) {
@@ -232,6 +371,52 @@ void TrayPower::UpdateAfterLoginStatusChange(user::LoginStatus status) {
void TrayPower::OnPowerStatusChanged(const PowerSupplyStatus& status) {
if (power_tray_)
power_tray_->UpdatePowerStatus(status);
+ if (notification_view_)
+ notification_view_->UpdatePowerStatus(status);
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAuraNotify)) {
+ if (UpdateNotificationState(status))
+ ShowNotificationView();
+ else if (notification_state_ == NOTIFICATION_NONE)
+ HideNotificationView();
+ }
+}
+
+bool TrayPower::UpdateNotificationState(const PowerSupplyStatus& status) {
+ if (!status.battery_is_present ||
+ status.is_calculating_battery_time ||
+ status.line_power_on) {
+ notification_state_ = NOTIFICATION_NONE;
+ return false;
+ }
+
+ int remaining_seconds = status.battery_seconds_to_empty;
+ if (remaining_seconds >= kNoWarningSeconds) {
+ notification_state_ = NOTIFICATION_NONE;
+ return false;
+ }
+
+ switch (notification_state_) {
+ case NOTIFICATION_NONE:
+ if (remaining_seconds <= kCriticalSeconds) {
+ notification_state_ = NOTIFICATION_CRITICAL;
+ return true;
+ } else if (remaining_seconds <= kLowPowerSeconds) {
+ notification_state_ = NOTIFICATION_LOW_POWER;
+ return true;
+ }
+ return false;
+ case NOTIFICATION_LOW_POWER:
+ if (remaining_seconds <= kCriticalSeconds) {
+ notification_state_ = NOTIFICATION_CRITICAL;
+ return true;
+ }
+ return false;
+ case NOTIFICATION_CRITICAL:
+ return false;
+ }
+ NOTREACHED();
+ return false;
}
} // namespace internal
diff --git a/ash/system/power/tray_power.h b/ash/system/power/tray_power.h
index 7c8f576..864d14e 100644
--- a/ash/system/power/tray_power.h
+++ b/ash/system/power/tray_power.h
@@ -13,6 +13,7 @@ namespace ash {
namespace internal {
namespace tray {
+class PowerNotificationView;
class PowerTrayView;
}
@@ -23,19 +24,31 @@ class TrayPower : public SystemTrayItem,
virtual ~TrayPower();
private:
+ enum NotificationState {
+ NOTIFICATION_NONE,
+ NOTIFICATION_LOW_POWER,
+ NOTIFICATION_CRITICAL
+ };
+
// Overridden from SystemTrayItem.
virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE;
virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE;
- virtual views::View* CreateDetailedView(user::LoginStatus status) OVERRIDE;
+ virtual views::View* CreateNotificationView(
+ user::LoginStatus status) OVERRIDE;
virtual void DestroyTrayView() OVERRIDE;
virtual void DestroyDefaultView() OVERRIDE;
- virtual void DestroyDetailedView() OVERRIDE;
+ virtual void DestroyNotificationView() OVERRIDE;
virtual void UpdateAfterLoginStatusChange(user::LoginStatus status) OVERRIDE;
// Overridden from PowerStatusObserver.
virtual void OnPowerStatusChanged(const PowerSupplyStatus& status) OVERRIDE;
+ // Sets |notification_state_|. Returns true if a notification should be shown.
+ bool UpdateNotificationState(const PowerSupplyStatus& status);
+
tray::PowerTrayView* power_tray_;
+ tray::PowerNotificationView* notification_view_;
+ NotificationState notification_state_;
DISALLOW_COPY_AND_ASSIGN(TrayPower);
};
diff --git a/ash/system/tray/tray_views.cc b/ash/system/tray/tray_views.cc
index 84f5f16..50aa8aa 100644
--- a/ash/system/tray/tray_views.cc
+++ b/ash/system/tray/tray_views.cc
@@ -8,14 +8,17 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "grit/ash_strings.h"
#include "grit/ui_resources.h"
+#include "grit/ui_resources_standard.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image.h"
#include "ui/views/border.h"
+#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
+#include "ui/views/layout/grid_layout.h"
#include "ui/views/painter.h"
namespace ash {
@@ -33,6 +36,7 @@ views::View* CreatePopupHeaderButtonsContainer() {
return view;
}
+const int kNotificationCloseButtonWidth = 60;
}
////////////////////////////////////////////////////////////////////////////////
@@ -448,5 +452,51 @@ void SetupLabelForTray(views::Label* label) {
label->SetShadowOffset(0, 1);
}
+////////////////////////////////////////////////////////////////////////////////
+// TrayNotificationView
+
+TrayNotificationView::TrayNotificationView() {
+}
+
+void TrayNotificationView::InitView(views::View* contents) {
+ set_background(views::Background::CreateSolidBackground(kBackgroundColor));
+
+ views::GridLayout* layout = new views::GridLayout(this);
+ SetLayoutManager(layout);
+
+ AddChildView(contents);
+
+ views::ImageButton* close_button = new views::ImageButton(this);
+ close_button->SetImage(views::CustomButton::BS_NORMAL,
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_AURA_WINDOW_CLOSE));
+ AddChildView(close_button);
+
+ int contents_width = kTrayPopupWidth - kNotificationCloseButtonWidth;
+ views::ColumnSet* columns = layout->AddColumnSet(0);
+ columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::FILL,
+ 0, /* resize percent */
+ views::GridLayout::FIXED,
+ contents_width,
+ contents_width);
+ columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
+ 0, /* resize percent */
+ views::GridLayout::FIXED,
+ kNotificationCloseButtonWidth,
+ kNotificationCloseButtonWidth);
+
+ layout->StartRow(0, 0);
+ layout->AddView(contents);
+ layout->AddView(close_button);
+}
+
+TrayNotificationView::~TrayNotificationView() {
+}
+
+void TrayNotificationView::ButtonPressed(views::Button* sender,
+ const views::Event& event) {
+ OnClose();
+}
+
} // namespace internal
} // namespace ash
diff --git a/ash/system/tray/tray_views.h b/ash/system/tray/tray_views.h
index dab672e..440036d 100644
--- a/ash/system/tray/tray_views.h
+++ b/ash/system/tray/tray_views.h
@@ -238,6 +238,30 @@ class SpecialPopupRow : public views::View {
DISALLOW_COPY_AND_ASSIGN(SpecialPopupRow);
};
+// A view for closable notification views, laid out like:
+// [ contents (x) ]
+// The close button will call OnClose() when pressed.
+class TrayNotificationView : public views::View,
+ public views::ButtonListener {
+ public:
+ TrayNotificationView();
+ virtual ~TrayNotificationView();
+
+ // InitView must be called once with the contents to be displayed.
+ void InitView(views::View* contents);
+
+ // Overridden from ButtonListener.
+ virtual void ButtonPressed(views::Button* sender,
+ const views::Event& event) OVERRIDE;
+
+ protected:
+ // Called when the closed button is pressed.
+ virtual void OnClose() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TrayNotificationView);
+};
+
// Sets up a Label properly for the tray (sets color, font etc.).
void SetupLabelForTray(views::Label* label);