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