Home | History | Annotate | Download | only in power
      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:
     20   MockMessageCenter() : add_count_(0), remove_count_(0) {}
     21   virtual ~MockMessageCenter() {}
     22 
     23   int add_count() const { return add_count_; }
     24   int remove_count() const { return remove_count_; }
     25 
     26   // message_center::FakeMessageCenter overrides:
     27   virtual void AddNotification(scoped_ptr<Notification> notification) OVERRIDE {
     28     add_count_++;
     29   }
     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:
     49   TrayPowerTest() {}
     50   virtual ~TrayPowerTest() {}
     51 
     52   MockMessageCenter* message_center() { return message_center_.get(); }
     53   TrayPower* tray_power() { return tray_power_.get(); }
     54 
     55   // test::AshTestBase::SetUp() overrides:
     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 
     62   virtual void TearDown() OVERRIDE {
     63     tray_power_.reset();
     64     message_center_.reset();
     65     test::AshTestBase::TearDown();
     66   }
     67 
     68   TrayPower::NotificationState notification_state() const {
     69     return tray_power_->notification_state_;
     70   }
     71 
     72   bool MaybeShowUsbChargerNotification(const PowerSupplyProperties& proto) {
     73     PowerStatus::Get()->SetProtoForTesting(proto);
     74     return tray_power_->MaybeShowUsbChargerNotification();
     75   }
     76 
     77   bool UpdateNotificationState(const PowerSupplyProperties& proto) {
     78     PowerStatus::Get()->SetProtoForTesting(proto);
     79     return tray_power_->UpdateNotificationState();
     80   }
     81 
     82   void SetUsbChargerConnected(bool connected) {
     83     tray_power_->usb_charger_was_connected_ = connected;
     84    }
     85 
     86   // Returns a discharging PowerSupplyProperties more appropriate for testing.
     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 
    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 
    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