• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "ash/system/chromeos/power/tray_power.h"
6 
7 #include "ash/ash_switches.h"
8 #include "ash/test/ash_test_base.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
11 #include "ui/message_center/fake_message_center.h"
12 
13 using message_center::Notification;
14 using power_manager::PowerSupplyProperties;
15 
16 namespace {
17 
18 class MockMessageCenter : public message_center::FakeMessageCenter {
19  public:
MockMessageCenter()20   MockMessageCenter() : add_count_(0), remove_count_(0) {}
~MockMessageCenter()21   virtual ~MockMessageCenter() {}
22 
add_count() const23   int add_count() const { return add_count_; }
remove_count() const24   int remove_count() const { return remove_count_; }
25 
26   // message_center::FakeMessageCenter overrides:
AddNotification(scoped_ptr<Notification> notification)27   virtual void AddNotification(scoped_ptr<Notification> notification) OVERRIDE {
28     add_count_++;
29   }
RemoveNotification(const std::string & id,bool by_user)30   virtual void RemoveNotification(const std::string& id, bool by_user)
31       OVERRIDE {
32     remove_count_++;
33   }
34 
35  private:
36   int add_count_;
37   int remove_count_;
38 
39   DISALLOW_COPY_AND_ASSIGN(MockMessageCenter);
40 };
41 
42 }  // namespace
43 
44 namespace ash {
45 namespace internal {
46 
47 class TrayPowerTest : public test::AshTestBase {
48  public:
TrayPowerTest()49   TrayPowerTest() {}
~TrayPowerTest()50   virtual ~TrayPowerTest() {}
51 
message_center()52   MockMessageCenter* message_center() { return message_center_.get(); }
tray_power()53   TrayPower* tray_power() { return tray_power_.get(); }
54 
55   // test::AshTestBase::SetUp() overrides:
SetUp()56   virtual void SetUp() OVERRIDE {
57     test::AshTestBase::SetUp();
58     message_center_.reset(new MockMessageCenter());
59     tray_power_.reset(new TrayPower(NULL, message_center_.get()));
60   }
61 
TearDown()62   virtual void TearDown() OVERRIDE {
63     tray_power_.reset();
64     message_center_.reset();
65     test::AshTestBase::TearDown();
66   }
67 
notification_state() const68   TrayPower::NotificationState notification_state() const {
69     return tray_power_->notification_state_;
70   }
71 
MaybeShowUsbChargerNotification(const PowerSupplyProperties & proto)72   bool MaybeShowUsbChargerNotification(const PowerSupplyProperties& proto) {
73     PowerStatus::Get()->SetProtoForTesting(proto);
74     return tray_power_->MaybeShowUsbChargerNotification();
75   }
76 
UpdateNotificationState(const PowerSupplyProperties & proto)77   bool UpdateNotificationState(const PowerSupplyProperties& proto) {
78     PowerStatus::Get()->SetProtoForTesting(proto);
79     return tray_power_->UpdateNotificationState();
80   }
81 
SetUsbChargerConnected(bool connected)82   void SetUsbChargerConnected(bool connected) {
83     tray_power_->usb_charger_was_connected_ = connected;
84    }
85 
86   // Returns a discharging PowerSupplyProperties more appropriate for testing.
DefaultPowerSupplyProperties()87   static PowerSupplyProperties DefaultPowerSupplyProperties() {
88     PowerSupplyProperties proto;
89     proto.set_external_power(
90         power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED);
91     proto.set_battery_state(
92         power_manager::PowerSupplyProperties_BatteryState_DISCHARGING);
93     proto.set_battery_percent(50.0);
94     proto.set_battery_time_to_empty_sec(3 * 60 * 60);
95     proto.set_battery_time_to_full_sec(2 * 60 * 60);
96     proto.set_is_calculating_battery_time(false);
97     return proto;
98   }
99 
100  private:
101   scoped_ptr<MockMessageCenter> message_center_;
102   scoped_ptr<TrayPower> tray_power_;
103 
104   DISALLOW_COPY_AND_ASSIGN(TrayPowerTest);
105 };
106 
TEST_F(TrayPowerTest,MaybeShowUsbChargerNotification)107 TEST_F(TrayPowerTest, MaybeShowUsbChargerNotification) {
108   PowerSupplyProperties discharging = DefaultPowerSupplyProperties();
109   EXPECT_FALSE(MaybeShowUsbChargerNotification(discharging));
110   EXPECT_EQ(0, message_center()->add_count());
111   EXPECT_EQ(0, message_center()->remove_count());
112 
113   // Notification shows when connecting a USB charger.
114   PowerSupplyProperties usb_connected = DefaultPowerSupplyProperties();
115   usb_connected.set_external_power(
116       power_manager::PowerSupplyProperties_ExternalPower_USB);
117   EXPECT_TRUE(MaybeShowUsbChargerNotification(usb_connected));
118   EXPECT_EQ(1, message_center()->add_count());
119   EXPECT_EQ(0, message_center()->remove_count());
120 
121   // Change in charge does not trigger the notification again.
122   PowerSupplyProperties more_charge = DefaultPowerSupplyProperties();
123   more_charge.set_external_power(
124       power_manager::PowerSupplyProperties_ExternalPower_USB);
125   more_charge.set_battery_time_to_full_sec(60 * 60);
126   more_charge.set_battery_percent(75.0);
127   SetUsbChargerConnected(true);
128   EXPECT_FALSE(MaybeShowUsbChargerNotification(more_charge));
129   EXPECT_EQ(1, message_center()->add_count());
130   EXPECT_EQ(0, message_center()->remove_count());
131 
132   // Disconnecting a USB charger with the notification showing should close
133   // the notification.
134   EXPECT_TRUE(MaybeShowUsbChargerNotification(discharging));
135   EXPECT_EQ(1, message_center()->add_count());
136   EXPECT_EQ(1, message_center()->remove_count());
137 }
138 
TEST_F(TrayPowerTest,UpdateNotificationState)139 TEST_F(TrayPowerTest, UpdateNotificationState) {
140   // No notifications when no battery present.
141   PowerSupplyProperties no_battery = DefaultPowerSupplyProperties();
142   no_battery.set_external_power(
143       power_manager::PowerSupplyProperties_ExternalPower_AC);
144   no_battery.set_battery_state(
145       power_manager::PowerSupplyProperties_BatteryState_NOT_PRESENT);
146   EXPECT_FALSE(UpdateNotificationState(no_battery));
147   EXPECT_EQ(TrayPower::NOTIFICATION_NONE, notification_state());
148 
149   // No notification when calculating remaining battery time.
150   PowerSupplyProperties calculating = DefaultPowerSupplyProperties();
151   calculating.set_is_calculating_battery_time(true);
152   EXPECT_FALSE(UpdateNotificationState(calculating));
153   EXPECT_EQ(TrayPower::NOTIFICATION_NONE, notification_state());
154 
155   // No notification when charging.
156   PowerSupplyProperties charging = DefaultPowerSupplyProperties();
157   charging.set_external_power(
158       power_manager::PowerSupplyProperties_ExternalPower_AC);
159   charging.set_battery_state(
160       power_manager::PowerSupplyProperties_BatteryState_CHARGING);
161   EXPECT_FALSE(UpdateNotificationState(charging));
162   EXPECT_EQ(TrayPower::NOTIFICATION_NONE, notification_state());
163 
164   // When the rounded minutes-to-empty are above the threshold, no notification
165   // should be shown.
166   PowerSupplyProperties low = DefaultPowerSupplyProperties();
167   low.set_battery_time_to_empty_sec(TrayPower::kLowPowerMinutes * 60 + 30);
168   EXPECT_FALSE(UpdateNotificationState(low));
169   EXPECT_EQ(TrayPower::NOTIFICATION_NONE, notification_state());
170 
171   // When the rounded value matches the threshold, the notification should
172   // appear.
173   low.set_battery_time_to_empty_sec(TrayPower::kLowPowerMinutes * 60 + 29);
174   EXPECT_TRUE(UpdateNotificationState(low));
175   EXPECT_EQ(TrayPower::NOTIFICATION_LOW_POWER, notification_state());
176 
177   // It should persist at lower values.
178   low.set_battery_time_to_empty_sec(TrayPower::kLowPowerMinutes * 60 - 20);
179   EXPECT_FALSE(UpdateNotificationState(low));
180   EXPECT_EQ(TrayPower::NOTIFICATION_LOW_POWER, notification_state());
181 
182   // The critical low battery notification should be shown when the rounded
183   // value is at the lower threshold.
184   PowerSupplyProperties critical = DefaultPowerSupplyProperties();
185   critical.set_battery_time_to_empty_sec(TrayPower::kCriticalMinutes * 60 + 29);
186   EXPECT_TRUE(UpdateNotificationState(critical));
187   EXPECT_EQ(TrayPower::NOTIFICATION_CRITICAL, notification_state());
188 
189   // The notification should be dismissed when the no-warning threshold is
190   // reached.
191   PowerSupplyProperties safe = DefaultPowerSupplyProperties();
192   safe.set_battery_time_to_empty_sec(TrayPower::kNoWarningMinutes * 60 - 29);
193   EXPECT_FALSE(UpdateNotificationState(safe));
194   EXPECT_EQ(TrayPower::NOTIFICATION_NONE, notification_state());
195 
196   // Test that rounded percentages are used when a USB charger is connected.
197   PowerSupplyProperties low_usb = DefaultPowerSupplyProperties();
198   low_usb.set_external_power(
199       power_manager::PowerSupplyProperties_ExternalPower_USB);
200   low_usb.set_battery_percent(TrayPower::kLowPowerPercentage + 0.5);
201   EXPECT_FALSE(UpdateNotificationState(low_usb));
202   EXPECT_EQ(TrayPower::NOTIFICATION_NONE, notification_state());
203 
204   low_usb.set_battery_percent(TrayPower::kLowPowerPercentage + 0.49);
205   EXPECT_TRUE(UpdateNotificationState(low_usb));
206   EXPECT_EQ(TrayPower::NOTIFICATION_LOW_POWER, notification_state());
207 
208   PowerSupplyProperties critical_usb = DefaultPowerSupplyProperties();
209   critical_usb.set_external_power(
210       power_manager::PowerSupplyProperties_ExternalPower_USB);
211   critical_usb.set_battery_percent(TrayPower::kCriticalPercentage + 0.2);
212   EXPECT_TRUE(UpdateNotificationState(critical_usb));
213   EXPECT_EQ(TrayPower::NOTIFICATION_CRITICAL, notification_state());
214 
215   PowerSupplyProperties safe_usb = DefaultPowerSupplyProperties();
216   safe_usb.set_external_power(
217       power_manager::PowerSupplyProperties_ExternalPower_USB);
218   safe_usb.set_battery_percent(TrayPower::kNoWarningPercentage - 0.1);
219   EXPECT_FALSE(UpdateNotificationState(safe_usb));
220   EXPECT_EQ(TrayPower::NOTIFICATION_NONE, notification_state());
221 
222   // A notification shouldn't be shown when we're in the full state with an
223   // original Spring charger connected: http://crbug.com/338376
224   PowerSupplyProperties spring = DefaultPowerSupplyProperties();
225   spring.set_external_power(power_manager::
226       PowerSupplyProperties_ExternalPower_ORIGINAL_SPRING_CHARGER);
227   spring.set_battery_state(
228       power_manager::PowerSupplyProperties_BatteryState_FULL);
229   spring.set_battery_time_to_empty_sec(0);
230   spring.set_battery_time_to_full_sec(0);
231   EXPECT_FALSE(UpdateNotificationState(spring));
232   EXPECT_EQ(TrayPower::NOTIFICATION_NONE, notification_state());
233 }
234 
235 }  // namespace internal
236 }  // namespace ash
237