- add sources.
[platform/framework/web/crosswalk.git] / src / ash / system / chromeos / power / tray_power.cc
1 // Copyright (c) 2012 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 "ash/system/chromeos/power/tray_power.h"
6
7 #include "ash/ash_switches.h"
8 #include "ash/system/chromeos/power/power_status_view.h"
9 #include "ash/system/date/date_view.h"
10 #include "ash/system/system_notifier.h"
11 #include "ash/system/tray/tray_constants.h"
12 #include "ash/system/tray/tray_notification_view.h"
13 #include "ash/system/tray/tray_utils.h"
14 #include "base/command_line.h"
15 #include "grit/ash_resources.h"
16 #include "grit/ash_strings.h"
17 #include "third_party/icu/source/i18n/unicode/fieldpos.h"
18 #include "third_party/icu/source/i18n/unicode/fmtable.h"
19 #include "ui/base/accessibility/accessible_view_state.h"
20 #include "ui/base/resource/resource_bundle.h"
21 #include "ui/message_center/message_center.h"
22 #include "ui/message_center/notification.h"
23 #include "ui/views/controls/button/button.h"
24 #include "ui/views/controls/image_view.h"
25 #include "ui/views/controls/label.h"
26 #include "ui/views/layout/box_layout.h"
27 #include "ui/views/layout/fill_layout.h"
28 #include "ui/views/layout/grid_layout.h"
29 #include "ui/views/view.h"
30 #include "ui/views/widget/widget.h"
31
32 using message_center::MessageCenter;
33 using message_center::Notification;
34
35 namespace ash {
36 namespace internal {
37 namespace tray {
38
39 // This view is used only for the tray.
40 class PowerTrayView : public views::ImageView {
41  public:
42   PowerTrayView() {
43     UpdateImage();
44   }
45
46   virtual ~PowerTrayView() {
47   }
48
49   // Overriden from views::View.
50   virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE {
51     state->name = accessible_name_;
52     state->role = ui::AccessibilityTypes::ROLE_PUSHBUTTON;
53   }
54
55   void UpdateStatus(bool battery_alert) {
56     UpdateImage();
57     SetVisible(PowerStatus::Get()->IsBatteryPresent());
58
59     if (battery_alert) {
60       accessible_name_ = PowerStatus::Get()->GetAccessibleNameString();
61       NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_ALERT, true);
62     }
63   }
64
65  private:
66   void UpdateImage() {
67     SetImage(PowerStatus::Get()->GetBatteryImage(PowerStatus::ICON_LIGHT));
68   }
69
70   base::string16 accessible_name_;
71
72   DISALLOW_COPY_AND_ASSIGN(PowerTrayView);
73 };
74
75 class PowerNotificationView : public TrayNotificationView {
76  public:
77   explicit PowerNotificationView(TrayPower* owner)
78       : TrayNotificationView(owner, 0) {
79     power_status_view_ =
80         new PowerStatusView(PowerStatusView::VIEW_NOTIFICATION, true);
81     InitView(power_status_view_);
82   }
83
84   void UpdateStatus() {
85     SetIconImage(PowerStatus::Get()->GetBatteryImage(PowerStatus::ICON_DARK));
86   }
87
88  private:
89   PowerStatusView* power_status_view_;
90
91   DISALLOW_COPY_AND_ASSIGN(PowerNotificationView);
92 };
93
94 }  // namespace tray
95
96 using tray::PowerNotificationView;
97
98 const int TrayPower::kCriticalMinutes = 5;
99 const int TrayPower::kLowPowerMinutes = 15;
100 const int TrayPower::kNoWarningMinutes = 30;
101 const int TrayPower::kCriticalPercentage = 5;
102 const int TrayPower::kLowPowerPercentage = 10;
103 const int TrayPower::kNoWarningPercentage = 15;
104
105 TrayPower::TrayPower(SystemTray* system_tray, MessageCenter* message_center)
106     : SystemTrayItem(system_tray),
107       message_center_(message_center),
108       power_tray_(NULL),
109       notification_view_(NULL),
110       notification_state_(NOTIFICATION_NONE),
111       usb_charger_was_connected_(false) {
112   PowerStatus::Get()->AddObserver(this);
113 }
114
115 TrayPower::~TrayPower() {
116   PowerStatus::Get()->RemoveObserver(this);
117 }
118
119 views::View* TrayPower::CreateTrayView(user::LoginStatus status) {
120   // There may not be enough information when this is created about whether
121   // there is a battery or not. So always create this, and adjust visibility as
122   // necessary.
123   CHECK(power_tray_ == NULL);
124   power_tray_ = new tray::PowerTrayView();
125   power_tray_->UpdateStatus(false);
126   return power_tray_;
127 }
128
129 views::View* TrayPower::CreateDefaultView(user::LoginStatus status) {
130   // Make sure icon status is up-to-date. (Also triggers stub activation).
131   PowerStatus::Get()->RequestStatusUpdate();
132   return NULL;
133 }
134
135 views::View* TrayPower::CreateNotificationView(user::LoginStatus status) {
136   CHECK(notification_view_ == NULL);
137   if (!PowerStatus::Get()->IsBatteryPresent())
138     return NULL;
139
140   notification_view_ = new PowerNotificationView(this);
141   notification_view_->UpdateStatus();
142
143   return notification_view_;
144 }
145
146 void TrayPower::DestroyTrayView() {
147   power_tray_ = NULL;
148 }
149
150 void TrayPower::DestroyDefaultView() {
151 }
152
153 void TrayPower::DestroyNotificationView() {
154   notification_view_ = NULL;
155 }
156
157 void TrayPower::UpdateAfterLoginStatusChange(user::LoginStatus status) {
158 }
159
160 void TrayPower::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
161   SetTrayImageItemBorder(power_tray_, alignment);
162 }
163
164 void TrayPower::OnPowerStatusChanged() {
165   bool battery_alert = UpdateNotificationState();
166   if (power_tray_)
167     power_tray_->UpdateStatus(battery_alert);
168   if (notification_view_)
169     notification_view_->UpdateStatus();
170
171   // Factory testing may place the battery into unusual states.
172   if (CommandLine::ForCurrentProcess()->HasSwitch(
173           ash::switches::kAshHideNotificationsForFactory))
174     return;
175
176   if (ash::switches::UseUsbChargerNotification())
177     MaybeShowUsbChargerNotification();
178
179   if (battery_alert)
180     ShowNotificationView();
181   else if (notification_state_ == NOTIFICATION_NONE)
182     HideNotificationView();
183
184   usb_charger_was_connected_ = PowerStatus::Get()->IsUsbChargerConnected();
185 }
186
187 bool TrayPower::MaybeShowUsbChargerNotification() {
188   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
189   const char kNotificationId[] = "usb-charger";
190   bool usb_charger_is_connected = PowerStatus::Get()->IsUsbChargerConnected();
191
192   // Check for a USB charger being connected.
193   if (usb_charger_is_connected && !usb_charger_was_connected_) {
194     scoped_ptr<Notification> notification(new Notification(
195         message_center::NOTIFICATION_TYPE_SIMPLE,
196         kNotificationId,
197         rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_LOW_POWER_CHARGER_TITLE),
198         rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_LOW_POWER_CHARGER_MESSAGE),
199         rb.GetImageNamed(IDR_AURA_NOTIFICATION_LOW_POWER_CHARGER),
200         base::string16(),
201         message_center::NotifierId(system_notifier::NOTIFIER_POWER),
202         message_center::RichNotificationData(),
203         NULL));
204     message_center_->AddNotification(notification.Pass());
205     return true;
206   }
207
208   // Check for unplug of a USB charger while the USB charger notification is
209   // showing.
210   if (!usb_charger_is_connected && usb_charger_was_connected_) {
211     message_center_->RemoveNotification(kNotificationId, false);
212     return true;
213   }
214   return false;
215 }
216
217 bool TrayPower::UpdateNotificationState() {
218   const PowerStatus& status = *PowerStatus::Get();
219   if (!status.IsBatteryPresent() ||
220       status.IsBatteryTimeBeingCalculated() ||
221       status.IsMainsChargerConnected()) {
222     notification_state_ = NOTIFICATION_NONE;
223     return false;
224   }
225
226   return status.IsUsbChargerConnected() ?
227       UpdateNotificationStateForRemainingPercentage() :
228       UpdateNotificationStateForRemainingTime();
229 }
230
231 bool TrayPower::UpdateNotificationStateForRemainingTime() {
232   // The notification includes a rounded minutes value, so round the estimate
233   // received from the power manager to match.
234   const int remaining_minutes = static_cast<int>(
235       PowerStatus::Get()->GetBatteryTimeToEmpty().InSecondsF() / 60.0 + 0.5);
236
237   if (remaining_minutes >= kNoWarningMinutes) {
238     notification_state_ = NOTIFICATION_NONE;
239     return false;
240   }
241
242   switch (notification_state_) {
243     case NOTIFICATION_NONE:
244       if (remaining_minutes <= kCriticalMinutes) {
245         notification_state_ = NOTIFICATION_CRITICAL;
246         return true;
247       }
248       if (remaining_minutes <= kLowPowerMinutes) {
249         notification_state_ = NOTIFICATION_LOW_POWER;
250         return true;
251       }
252       return false;
253     case NOTIFICATION_LOW_POWER:
254       if (remaining_minutes <= kCriticalMinutes) {
255         notification_state_ = NOTIFICATION_CRITICAL;
256         return true;
257       }
258       return false;
259     case NOTIFICATION_CRITICAL:
260       return false;
261   }
262   NOTREACHED();
263   return false;
264 }
265
266 bool TrayPower::UpdateNotificationStateForRemainingPercentage() {
267   // The notification includes a rounded percentage, so round the value received
268   // from the power manager to match.
269   const int remaining_percentage =
270       PowerStatus::Get()->GetRoundedBatteryPercent();
271
272   if (remaining_percentage >= kNoWarningPercentage) {
273     notification_state_ = NOTIFICATION_NONE;
274     return false;
275   }
276
277   switch (notification_state_) {
278     case NOTIFICATION_NONE:
279       if (remaining_percentage <= kCriticalPercentage) {
280         notification_state_ = NOTIFICATION_CRITICAL;
281         return true;
282       }
283       if (remaining_percentage <= kLowPowerPercentage) {
284         notification_state_ = NOTIFICATION_LOW_POWER;
285         return true;
286       }
287       return false;
288     case NOTIFICATION_LOW_POWER:
289       if (remaining_percentage <= kCriticalPercentage) {
290         notification_state_ = NOTIFICATION_CRITICAL;
291         return true;
292       }
293       return false;
294     case NOTIFICATION_CRITICAL:
295       return false;
296   }
297   NOTREACHED();
298   return false;
299 }
300
301 }  // namespace internal
302 }  // namespace ash