Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(601)

Side by Side Diff: ash/common/system/chromeos/power/tray_power.cc

Issue 2734653002: chromeos: Move files in //ash/common to //ash (Closed)
Patch Set: fix a11y tests, fix docs Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/common/system/chromeos/power/tray_power.h"
6
7 #include <utility>
8
9 #include "ash/common/accessibility_delegate.h"
10 #include "ash/common/ash_switches.h"
11 #include "ash/common/system/chromeos/devicetype_utils.h"
12 #include "ash/common/system/chromeos/power/battery_notification.h"
13 #include "ash/common/system/chromeos/power/dual_role_notification.h"
14 #include "ash/common/system/date/date_view.h"
15 #include "ash/common/system/system_notifier.h"
16 #include "ash/common/system/tray/system_tray_delegate.h"
17 #include "ash/common/system/tray/tray_constants.h"
18 #include "ash/common/system/tray/tray_item_view.h"
19 #include "ash/common/system/tray/tray_utils.h"
20 #include "ash/resources/grit/ash_resources.h"
21 #include "ash/strings/grit/ash_strings.h"
22 #include "base/command_line.h"
23 #include "base/logging.h"
24 #include "base/metrics/histogram.h"
25 #include "base/time/time.h"
26 #include "ui/accessibility/ax_node_data.h"
27 #include "ui/base/resource/resource_bundle.h"
28 #include "ui/message_center/message_center.h"
29 #include "ui/message_center/notification.h"
30 #include "ui/message_center/notification_delegate.h"
31 #include "ui/views/controls/image_view.h"
32 #include "ui/views/view.h"
33
34 using message_center::MessageCenter;
35 using message_center::Notification;
36
37 namespace ash {
38
39 // Informs the TrayPower instance when a USB notification is closed.
40 class UsbNotificationDelegate : public message_center::NotificationDelegate {
41 public:
42 explicit UsbNotificationDelegate(TrayPower* tray_power)
43 : tray_power_(tray_power) {}
44
45 // Overridden from message_center::NotificationDelegate.
46 void Close(bool by_user) override {
47 if (by_user)
48 tray_power_->NotifyUsbNotificationClosedByUser();
49 }
50
51 private:
52 ~UsbNotificationDelegate() override {}
53
54 TrayPower* tray_power_;
55
56 DISALLOW_COPY_AND_ASSIGN(UsbNotificationDelegate);
57 };
58
59 namespace {
60
61 std::string GetNotificationStateString(
62 TrayPower::NotificationState notification_state) {
63 switch (notification_state) {
64 case TrayPower::NOTIFICATION_NONE:
65 return "none";
66 case TrayPower::NOTIFICATION_LOW_POWER:
67 return "low power";
68 case TrayPower::NOTIFICATION_CRITICAL:
69 return "critical power";
70 }
71 NOTREACHED() << "Unknown state " << notification_state;
72 return "Unknown state";
73 }
74
75 void LogBatteryForUsbCharger(TrayPower::NotificationState state,
76 int battery_percent) {
77 LOG(WARNING) << "Showing " << GetNotificationStateString(state)
78 << " notification. USB charger is connected. "
79 << "Battery percentage: " << battery_percent << "%.";
80 }
81
82 void LogBatteryForNoCharger(TrayPower::NotificationState state,
83 int remaining_minutes) {
84 LOG(WARNING) << "Showing " << GetNotificationStateString(state)
85 << " notification. No charger connected."
86 << " Remaining time: " << remaining_minutes << " minutes.";
87 }
88
89 } // namespace
90
91 namespace tray {
92
93 // This view is used only for the tray.
94 class PowerTrayView : public TrayItemView {
95 public:
96 explicit PowerTrayView(SystemTrayItem* owner) : TrayItemView(owner) {
97 CreateImageView();
98 UpdateImage();
99 }
100
101 ~PowerTrayView() override {}
102
103 // Overriden from views::View.
104 void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
105 node_data->SetName(accessible_name_);
106 node_data->role = ui::AX_ROLE_BUTTON;
107 }
108
109 void UpdateStatus(bool battery_alert) {
110 UpdateImage();
111 SetVisible(PowerStatus::Get()->IsBatteryPresent());
112
113 if (battery_alert) {
114 accessible_name_ = PowerStatus::Get()->GetAccessibleNameString(true);
115 NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true);
116 }
117 }
118
119 private:
120 void UpdateImage() {
121 const PowerStatus::BatteryImageInfo info =
122 PowerStatus::Get()->GetBatteryImageInfo(PowerStatus::ICON_LIGHT);
123 if (info != previous_image_info_) {
124 image_view()->SetImage(PowerStatus::Get()->GetBatteryImage(info));
125 previous_image_info_ = info;
126 }
127 }
128
129 base::string16 accessible_name_;
130
131 // Information about the last-used image. Cached to avoid unnecessary updates
132 // (http://crbug.com/589348).
133 PowerStatus::BatteryImageInfo previous_image_info_;
134
135 DISALLOW_COPY_AND_ASSIGN(PowerTrayView);
136 };
137
138 } // namespace tray
139
140 const int TrayPower::kCriticalMinutes = 5;
141 const int TrayPower::kLowPowerMinutes = 15;
142 const int TrayPower::kNoWarningMinutes = 30;
143 const int TrayPower::kCriticalPercentage = 5;
144 const int TrayPower::kLowPowerPercentage = 10;
145 const int TrayPower::kNoWarningPercentage = 15;
146
147 const char TrayPower::kUsbNotificationId[] = "usb-charger";
148
149 TrayPower::TrayPower(SystemTray* system_tray, MessageCenter* message_center)
150 : SystemTrayItem(system_tray, UMA_POWER),
151 message_center_(message_center),
152 power_tray_(NULL),
153 notification_state_(NOTIFICATION_NONE),
154 usb_charger_was_connected_(false),
155 line_power_was_connected_(false),
156 usb_notification_dismissed_(false) {
157 PowerStatus::Get()->AddObserver(this);
158 }
159
160 TrayPower::~TrayPower() {
161 PowerStatus::Get()->RemoveObserver(this);
162 message_center_->RemoveNotification(kUsbNotificationId, false);
163 }
164
165 views::View* TrayPower::CreateTrayView(LoginStatus status) {
166 // There may not be enough information when this is created about whether
167 // there is a battery or not. So always create this, and adjust visibility as
168 // necessary.
169 CHECK(power_tray_ == NULL);
170 power_tray_ = new tray::PowerTrayView(this);
171 power_tray_->UpdateStatus(false);
172 return power_tray_;
173 }
174
175 views::View* TrayPower::CreateDefaultView(LoginStatus status) {
176 // Make sure icon status is up to date. (Also triggers stub activation).
177 PowerStatus::Get()->RequestStatusUpdate();
178 return NULL;
179 }
180
181 void TrayPower::DestroyTrayView() {
182 power_tray_ = NULL;
183 }
184
185 void TrayPower::DestroyDefaultView() {}
186
187 void TrayPower::UpdateAfterLoginStatusChange(LoginStatus status) {}
188
189 void TrayPower::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
190 SetTrayImageItemBorder(power_tray_, alignment);
191 }
192
193 void TrayPower::OnPowerStatusChanged() {
194 bool battery_alert = UpdateNotificationState();
195 if (power_tray_)
196 power_tray_->UpdateStatus(battery_alert);
197
198 // Factory testing may place the battery into unusual states.
199 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
200 ash::switches::kAshHideNotificationsForFactory))
201 return;
202
203 MaybeShowUsbChargerNotification();
204 MaybeShowDualRoleNotification();
205
206 if (battery_alert) {
207 // Remove any existing notification so it's dismissed before adding a new
208 // one. Otherwise we might update a "low battery" notification to "critical"
209 // without it being shown again.
210 battery_notification_.reset();
211 battery_notification_.reset(
212 new BatteryNotification(message_center_, notification_state_));
213 } else if (notification_state_ == NOTIFICATION_NONE) {
214 battery_notification_.reset();
215 } else if (battery_notification_.get()) {
216 battery_notification_->Update(notification_state_);
217 }
218
219 usb_charger_was_connected_ = PowerStatus::Get()->IsUsbChargerConnected();
220 line_power_was_connected_ = PowerStatus::Get()->IsLinePowerConnected();
221 }
222
223 bool TrayPower::MaybeShowUsbChargerNotification() {
224 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
225 const PowerStatus& status = *PowerStatus::Get();
226
227 bool usb_charger_is_connected = status.IsUsbChargerConnected();
228
229 // Check for a USB charger being connected.
230 if (usb_charger_is_connected && !usb_charger_was_connected_ &&
231 !usb_notification_dismissed_) {
232 std::unique_ptr<Notification> notification(new Notification(
233 message_center::NOTIFICATION_TYPE_SIMPLE, kUsbNotificationId,
234 rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_LOW_POWER_CHARGER_TITLE),
235 ash::SubstituteChromeOSDeviceType(
236 IDS_ASH_STATUS_TRAY_LOW_POWER_CHARGER_MESSAGE_SHORT),
237 rb.GetImageNamed(IDR_AURA_NOTIFICATION_LOW_POWER_CHARGER),
238 base::string16(), GURL(),
239 message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT,
240 system_notifier::kNotifierPower),
241 message_center::RichNotificationData(),
242 new UsbNotificationDelegate(this)));
243 message_center_->AddNotification(std::move(notification));
244 return true;
245 } else if (!usb_charger_is_connected && usb_charger_was_connected_) {
246 // USB charger was unplugged or was identified as a different type while
247 // the USB charger notification was showing.
248 message_center_->RemoveNotification(kUsbNotificationId, false);
249 if (!status.IsLinePowerConnected())
250 usb_notification_dismissed_ = false;
251 return true;
252 }
253 return false;
254 }
255
256 void TrayPower::MaybeShowDualRoleNotification() {
257 const PowerStatus& status = *PowerStatus::Get();
258 if (!status.HasDualRoleDevices()) {
259 dual_role_notification_.reset();
260 return;
261 }
262
263 if (!dual_role_notification_)
264 dual_role_notification_.reset(new DualRoleNotification(message_center_));
265 dual_role_notification_->Update();
266 }
267
268 bool TrayPower::UpdateNotificationState() {
269 const PowerStatus& status = *PowerStatus::Get();
270 if (!status.IsBatteryPresent() || status.IsBatteryTimeBeingCalculated() ||
271 status.IsMainsChargerConnected()) {
272 notification_state_ = NOTIFICATION_NONE;
273 return false;
274 }
275
276 return status.IsUsbChargerConnected()
277 ? UpdateNotificationStateForRemainingPercentage()
278 : UpdateNotificationStateForRemainingTime();
279 }
280
281 bool TrayPower::UpdateNotificationStateForRemainingTime() {
282 // The notification includes a rounded minutes value, so round the estimate
283 // received from the power manager to match.
284 const int remaining_minutes = static_cast<int>(
285 PowerStatus::Get()->GetBatteryTimeToEmpty().InSecondsF() / 60.0 + 0.5);
286
287 if (remaining_minutes >= kNoWarningMinutes ||
288 PowerStatus::Get()->IsBatteryFull()) {
289 notification_state_ = NOTIFICATION_NONE;
290 return false;
291 }
292
293 switch (notification_state_) {
294 case NOTIFICATION_NONE:
295 if (remaining_minutes <= kCriticalMinutes) {
296 notification_state_ = NOTIFICATION_CRITICAL;
297 LogBatteryForNoCharger(notification_state_, remaining_minutes);
298 return true;
299 }
300 if (remaining_minutes <= kLowPowerMinutes) {
301 notification_state_ = NOTIFICATION_LOW_POWER;
302 LogBatteryForNoCharger(notification_state_, remaining_minutes);
303 return true;
304 }
305 return false;
306 case NOTIFICATION_LOW_POWER:
307 if (remaining_minutes <= kCriticalMinutes) {
308 notification_state_ = NOTIFICATION_CRITICAL;
309 LogBatteryForNoCharger(notification_state_, remaining_minutes);
310 return true;
311 }
312 return false;
313 case NOTIFICATION_CRITICAL:
314 return false;
315 }
316 NOTREACHED();
317 return false;
318 }
319
320 bool TrayPower::UpdateNotificationStateForRemainingPercentage() {
321 // The notification includes a rounded percentage, so round the value received
322 // from the power manager to match.
323 const int remaining_percentage =
324 PowerStatus::Get()->GetRoundedBatteryPercent();
325
326 if (remaining_percentage >= kNoWarningPercentage ||
327 PowerStatus::Get()->IsBatteryFull()) {
328 notification_state_ = NOTIFICATION_NONE;
329 return false;
330 }
331
332 switch (notification_state_) {
333 case NOTIFICATION_NONE:
334 if (remaining_percentage <= kCriticalPercentage) {
335 notification_state_ = NOTIFICATION_CRITICAL;
336 LogBatteryForUsbCharger(notification_state_, remaining_percentage);
337 return true;
338 }
339 if (remaining_percentage <= kLowPowerPercentage) {
340 notification_state_ = NOTIFICATION_LOW_POWER;
341 LogBatteryForUsbCharger(notification_state_, remaining_percentage);
342 return true;
343 }
344 return false;
345 case NOTIFICATION_LOW_POWER:
346 if (remaining_percentage <= kCriticalPercentage) {
347 notification_state_ = NOTIFICATION_CRITICAL;
348 LogBatteryForUsbCharger(notification_state_, remaining_percentage);
349 return true;
350 }
351 return false;
352 case NOTIFICATION_CRITICAL:
353 return false;
354 }
355 NOTREACHED();
356 return false;
357 }
358
359 void TrayPower::NotifyUsbNotificationClosedByUser() {
360 usb_notification_dismissed_ = true;
361 }
362
363 } // namespace ash
OLDNEW
« no previous file with comments | « ash/common/system/chromeos/power/tray_power.h ('k') | ash/common/system/chromeos/power/tray_power_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698