1 // Copyright 2013 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.
5 #include "ash/system/chromeos/power/tray_power.h"
10 #include "ash/ash_switches.h"
11 #include "ash/test/ash_test_base.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
14 #include "ui/message_center/fake_message_center.h"
16 using message_center::Notification
;
17 using power_manager::PowerSupplyProperties
;
21 class MockMessageCenter
: public message_center::FakeMessageCenter
{
23 MockMessageCenter() : add_count_(0), remove_count_(0) {}
24 ~MockMessageCenter() override
{}
26 int add_count() const { return add_count_
; }
27 int remove_count() const { return remove_count_
; }
29 // message_center::FakeMessageCenter overrides:
30 void AddNotification(scoped_ptr
<Notification
> notification
) override
{
32 notifications_
[notification
->id()] = notification
.get();
34 void RemoveNotification(const std::string
& id
, bool by_user
) override
{
36 notifications_
.erase(id
);
39 Notification
* FindVisibleNotificationById(const std::string
& id
) override
{
40 auto it
= notifications_
.find(id
);
41 return it
== notifications_
.end() ? NULL
: it
->second
;
47 std::map
<std::string
, Notification
*> notifications_
;
49 DISALLOW_COPY_AND_ASSIGN(MockMessageCenter
);
56 class TrayPowerTest
: public test::AshTestBase
{
59 ~TrayPowerTest() override
{}
61 MockMessageCenter
* message_center() { return message_center_
.get(); }
62 TrayPower
* tray_power() { return tray_power_
.get(); }
64 // test::AshTestBase::SetUp() overrides:
65 void SetUp() override
{
66 test::AshTestBase::SetUp();
67 message_center_
.reset(new MockMessageCenter());
68 tray_power_
.reset(new TrayPower(NULL
, message_center_
.get()));
71 void TearDown() override
{
73 message_center_
.reset();
74 test::AshTestBase::TearDown();
77 TrayPower::NotificationState
notification_state() const {
78 return tray_power_
->notification_state_
;
81 bool MaybeShowUsbChargerNotification(const PowerSupplyProperties
& proto
) {
82 PowerStatus::Get()->SetProtoForTesting(proto
);
83 return tray_power_
->MaybeShowUsbChargerNotification();
86 void UpdateNotificationState(const PowerSupplyProperties
& proto
,
87 TrayPower::NotificationState expected_state
,
89 bool expected_remove
) {
90 int prev_add
= message_center_
->add_count();
91 int prev_remove
= message_center_
->remove_count();
92 PowerStatus::Get()->SetProtoForTesting(proto
);
93 tray_power_
->OnPowerStatusChanged();
94 EXPECT_EQ(expected_state
, notification_state());
95 EXPECT_EQ(expected_add
, message_center_
->add_count() == prev_add
+ 1);
96 EXPECT_EQ(expected_remove
,
97 message_center_
->remove_count() == prev_remove
+ 1);
100 void SetUsbChargerConnected(bool connected
) {
101 tray_power_
->usb_charger_was_connected_
= connected
;
104 // Returns a discharging PowerSupplyProperties more appropriate for testing.
105 static PowerSupplyProperties
DefaultPowerSupplyProperties() {
106 PowerSupplyProperties proto
;
107 proto
.set_external_power(
108 power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED
);
109 proto
.set_battery_state(
110 power_manager::PowerSupplyProperties_BatteryState_DISCHARGING
);
111 proto
.set_battery_percent(50.0);
112 proto
.set_battery_time_to_empty_sec(3 * 60 * 60);
113 proto
.set_battery_time_to_full_sec(2 * 60 * 60);
114 proto
.set_is_calculating_battery_time(false);
119 scoped_ptr
<MockMessageCenter
> message_center_
;
120 scoped_ptr
<TrayPower
> tray_power_
;
122 DISALLOW_COPY_AND_ASSIGN(TrayPowerTest
);
125 TEST_F(TrayPowerTest
, MaybeShowUsbChargerNotification
) {
126 PowerSupplyProperties discharging
= DefaultPowerSupplyProperties();
127 EXPECT_FALSE(MaybeShowUsbChargerNotification(discharging
));
128 EXPECT_EQ(0, message_center()->add_count());
129 EXPECT_EQ(0, message_center()->remove_count());
131 // Notification shows when connecting a USB charger.
132 PowerSupplyProperties usb_connected
= DefaultPowerSupplyProperties();
133 usb_connected
.set_external_power(
134 power_manager::PowerSupplyProperties_ExternalPower_USB
);
135 EXPECT_TRUE(MaybeShowUsbChargerNotification(usb_connected
));
136 EXPECT_EQ(1, message_center()->add_count());
137 EXPECT_EQ(0, message_center()->remove_count());
139 // Change in charge does not trigger the notification again.
140 PowerSupplyProperties more_charge
= DefaultPowerSupplyProperties();
141 more_charge
.set_external_power(
142 power_manager::PowerSupplyProperties_ExternalPower_USB
);
143 more_charge
.set_battery_time_to_full_sec(60 * 60);
144 more_charge
.set_battery_percent(75.0);
145 SetUsbChargerConnected(true);
146 EXPECT_FALSE(MaybeShowUsbChargerNotification(more_charge
));
147 EXPECT_EQ(1, message_center()->add_count());
148 EXPECT_EQ(0, message_center()->remove_count());
150 // Disconnecting a USB charger with the notification showing should close
152 EXPECT_TRUE(MaybeShowUsbChargerNotification(discharging
));
153 EXPECT_EQ(1, message_center()->add_count());
154 EXPECT_EQ(1, message_center()->remove_count());
157 TEST_F(TrayPowerTest
, UpdateNotificationState
) {
158 // No notifications when no battery present.
159 PowerSupplyProperties no_battery
= DefaultPowerSupplyProperties();
160 no_battery
.set_external_power(
161 power_manager::PowerSupplyProperties_ExternalPower_AC
);
162 no_battery
.set_battery_state(
163 power_manager::PowerSupplyProperties_BatteryState_NOT_PRESENT
);
165 SCOPED_TRACE("No notifications when no battery present");
166 UpdateNotificationState(no_battery
, TrayPower::NOTIFICATION_NONE
, false,
170 // No notification when calculating remaining battery time.
171 PowerSupplyProperties calculating
= DefaultPowerSupplyProperties();
172 calculating
.set_is_calculating_battery_time(true);
174 SCOPED_TRACE("No notification when calculating remaining battery time");
175 UpdateNotificationState(calculating
, TrayPower::NOTIFICATION_NONE
, false,
179 // No notification when charging.
180 PowerSupplyProperties charging
= DefaultPowerSupplyProperties();
181 charging
.set_external_power(
182 power_manager::PowerSupplyProperties_ExternalPower_AC
);
183 charging
.set_battery_state(
184 power_manager::PowerSupplyProperties_BatteryState_CHARGING
);
186 SCOPED_TRACE("No notification when charging");
187 UpdateNotificationState(charging
, TrayPower::NOTIFICATION_NONE
, false,
191 // When the rounded minutes-to-empty are above the threshold, no notification
193 PowerSupplyProperties low
= DefaultPowerSupplyProperties();
194 low
.set_battery_time_to_empty_sec(TrayPower::kLowPowerMinutes
* 60 + 30);
196 SCOPED_TRACE("No notification when time to empty above threshold");
197 UpdateNotificationState(low
, TrayPower::NOTIFICATION_NONE
, false, false);
200 // When the rounded value matches the threshold, the notification should
202 low
.set_battery_time_to_empty_sec(TrayPower::kLowPowerMinutes
* 60 + 29);
204 SCOPED_TRACE("Notification when time to empty matches threshold");
205 UpdateNotificationState(low
, TrayPower::NOTIFICATION_LOW_POWER
, true,
209 // It should persist at lower values.
210 low
.set_battery_time_to_empty_sec(TrayPower::kLowPowerMinutes
* 60 - 20);
212 SCOPED_TRACE("Notification persists at lower values");
213 UpdateNotificationState(low
, TrayPower::NOTIFICATION_LOW_POWER
, false,
217 // The critical low battery notification should be shown when the rounded
218 // value is at the lower threshold.
219 PowerSupplyProperties critical
= DefaultPowerSupplyProperties();
220 critical
.set_battery_time_to_empty_sec(TrayPower::kCriticalMinutes
* 60 + 29);
222 SCOPED_TRACE("Critical notification when time to empty is critical");
223 UpdateNotificationState(critical
, TrayPower::NOTIFICATION_CRITICAL
, true,
227 // The notification should be dismissed when the no-warning threshold is
229 PowerSupplyProperties safe
= DefaultPowerSupplyProperties();
230 safe
.set_battery_time_to_empty_sec(TrayPower::kNoWarningMinutes
* 60 - 29);
232 SCOPED_TRACE("Notification removed when battery not low");
233 UpdateNotificationState(safe
, TrayPower::NOTIFICATION_NONE
, false, true);
236 // Test that rounded percentages are used when a USB charger is connected.
237 PowerSupplyProperties low_usb
= DefaultPowerSupplyProperties();
238 low_usb
.set_external_power(
239 power_manager::PowerSupplyProperties_ExternalPower_USB
);
240 low_usb
.set_battery_percent(TrayPower::kLowPowerPercentage
+ 0.5);
242 SCOPED_TRACE("No notification for rounded battery percent");
243 UpdateNotificationState(low_usb
, TrayPower::NOTIFICATION_NONE
, true, false);
246 low_usb
.set_battery_percent(TrayPower::kLowPowerPercentage
+ 0.49);
248 SCOPED_TRACE("Notification for rounded low power percent");
249 UpdateNotificationState(low_usb
, TrayPower::NOTIFICATION_LOW_POWER
, true,
253 PowerSupplyProperties critical_usb
= DefaultPowerSupplyProperties();
254 critical_usb
.set_external_power(
255 power_manager::PowerSupplyProperties_ExternalPower_USB
);
256 critical_usb
.set_battery_percent(TrayPower::kCriticalPercentage
+ 0.2);
258 SCOPED_TRACE("Notification for rounded critical power percent");
259 UpdateNotificationState(critical_usb
, TrayPower::NOTIFICATION_CRITICAL
,
263 PowerSupplyProperties safe_usb
= DefaultPowerSupplyProperties();
264 safe_usb
.set_external_power(
265 power_manager::PowerSupplyProperties_ExternalPower_USB
);
266 safe_usb
.set_battery_percent(TrayPower::kNoWarningPercentage
- 0.1);
268 SCOPED_TRACE("Notification removed for rounded percent above threshold");
269 UpdateNotificationState(safe_usb
, TrayPower::NOTIFICATION_NONE
, false,