| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/system/power/peripheral_battery_listener.h" |
| |
| #include <memory> |
| #include <string> |
| |
| #include "ash/shell.h" |
| #include "ash/system/power/peripheral_battery_notifier.h" |
| #include "ash/system/power/peripheral_battery_tests.h" |
| #include "ash/test/ash_test_base.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_piece.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/task_environment.h" |
| #include "device/bluetooth/bluetooth_device.h" |
| #include "device/bluetooth/test/mock_bluetooth_adapter.h" |
| #include "device/bluetooth/test/mock_bluetooth_device.h" |
| #include "ui/events/devices/device_data_manager.h" |
| #include "ui/events/devices/device_data_manager_test_api.h" |
| #include "ui/events/devices/touchscreen_device.h" |
| #include "ui/message_center/message_center.h" |
| #include "ui/message_center/public/cpp/notification.h" |
| |
| using testing::NiceMock; |
| |
| namespace { |
| |
| const std::u16string& NotificationMessagePrefix() { |
| static const std::u16string prefix(base::ASCIIToUTF16("Battery low (")); |
| return prefix; |
| } |
| |
| const std::u16string& NotificationMessageSuffix() { |
| static const std::u16string suffix(base::ASCIIToUTF16("%)")); |
| return suffix; |
| } |
| |
| } // namespace |
| |
| namespace ash { |
| |
| class PeripheralBatteryNotifierListenerTest : public AshTestBase { |
| public: |
| // Constants for active field of PeripheralBatteryStylusReceived(). |
| const bool kBluetoothBatteryUpdate = true; |
| const bool kBatteryPolledUpdate = false; |
| const bool kBatteryEventUpdate = true; |
| |
| PeripheralBatteryNotifierListenerTest() |
| : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} |
| PeripheralBatteryNotifierListenerTest( |
| const PeripheralBatteryNotifierListenerTest&) = delete; |
| PeripheralBatteryNotifierListenerTest& operator=( |
| const PeripheralBatteryNotifierListenerTest&) = delete; |
| ~PeripheralBatteryNotifierListenerTest() override = default; |
| |
| void SetUp() override { |
| ui::DeviceDataManager::CreateInstance(); |
| |
| AshTestBase::SetUp(); |
| |
| // Simulate the complete listing of input devices, required by the listener. |
| if (complete_devices_) |
| ui::DeviceDataManagerTestApi().OnDeviceListsComplete(); |
| |
| mock_adapter_ = |
| base::MakeRefCounted<NiceMock<device::MockBluetoothAdapter>>(); |
| mock_device_1_ = std::make_unique<NiceMock<device::MockBluetoothDevice>>( |
| mock_adapter_.get(), /*bluetooth_class=*/0, kBluetoothDeviceName1, |
| kBluetoothDeviceAddress1, /*paired=*/true, /*connected=*/true); |
| mock_device_2_ = std::make_unique<NiceMock<device::MockBluetoothDevice>>( |
| mock_adapter_.get(), /*bluetooth_class=*/0, kBluetoothDeviceName2, |
| kBluetoothDeviceAddress2, /*paired=*/true, /*connected=*/true); |
| |
| message_center_ = message_center::MessageCenter::Get(); |
| |
| battery_listener_ = std::make_unique<PeripheralBatteryListener>(); |
| battery_notifier_ = |
| std::make_unique<PeripheralBatteryNotifier>(battery_listener_.get()); |
| // No notifications should have been posted yet. |
| ASSERT_EQ(0u, message_center_->NotificationCount()); |
| } |
| |
| void TearDown() override { |
| battery_notifier_.reset(); |
| battery_listener_.reset(); |
| AshTestBase::TearDown(); |
| ui::DeviceDataManager::DeleteInstance(); |
| } |
| |
| void SendBatteryUpdate(const std::string& path, |
| const std::string& name, |
| int level) { |
| battery_listener_->PeripheralBatteryStatusReceived( |
| path, name, level, |
| power_manager:: |
| PeripheralBatteryStatus_ChargeStatus_CHARGE_STATUS_DISCHARGING, |
| kBatteryPolledUpdate); |
| } |
| |
| void SendBatteryUpdate( |
| const std::string& path, |
| const std::string& name, |
| int level, |
| power_manager::PeripheralBatteryStatus_ChargeStatus status, |
| bool active_update) { |
| battery_listener_->PeripheralBatteryStatusReceived(path, name, level, |
| status, active_update); |
| } |
| |
| // Extracts the battery percentage from the message of a notification. |
| uint8_t ExtractBatteryPercentage(message_center::Notification* notification) { |
| const std::u16string& message = notification->message(); |
| EXPECT_TRUE(base::StartsWith(message, NotificationMessagePrefix(), |
| base::CompareCase::SENSITIVE)); |
| EXPECT_TRUE(base::EndsWith(message, NotificationMessageSuffix(), |
| base::CompareCase::SENSITIVE)); |
| |
| int prefix_size = NotificationMessagePrefix().size(); |
| int suffix_size = NotificationMessageSuffix().size(); |
| int key_len = message.size() - prefix_size - suffix_size; |
| EXPECT_GT(key_len, 0); |
| |
| int battery_percentage; |
| EXPECT_TRUE(base::StringToInt(message.substr(prefix_size, key_len), |
| &battery_percentage)); |
| EXPECT_GE(battery_percentage, 0); |
| EXPECT_LE(battery_percentage, 100); |
| return battery_percentage; |
| } |
| |
| base::TimeTicks GetTestingClock() { return base::TimeTicks::Now(); } |
| |
| void ClockAdvance(base::TimeDelta delta) { |
| task_environment()->AdvanceClock(delta); |
| } |
| |
| protected: |
| scoped_refptr<NiceMock<device::MockBluetoothAdapter>> mock_adapter_; |
| std::unique_ptr<device::MockBluetoothDevice> mock_device_1_; |
| std::unique_ptr<device::MockBluetoothDevice> mock_device_2_; |
| message_center::MessageCenter* message_center_; |
| std::unique_ptr<PeripheralBatteryNotifier> battery_notifier_; |
| std::unique_ptr<PeripheralBatteryListener> battery_listener_; |
| |
| void set_complete_devices(bool complete_devices) { |
| complete_devices_ = complete_devices; |
| } |
| |
| // SetUp() doesn't complete devices if this is set to false. |
| bool complete_devices_ = true; |
| }; |
| |
| class PeripheralBatteryNotifierListenerIncompleteDevicesTest |
| : public PeripheralBatteryNotifierListenerTest { |
| public: |
| PeripheralBatteryNotifierListenerIncompleteDevicesTest() { |
| set_complete_devices(false); |
| } |
| ~PeripheralBatteryNotifierListenerIncompleteDevicesTest() override {} |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN( |
| PeripheralBatteryNotifierListenerIncompleteDevicesTest); |
| }; |
| |
| TEST_F(PeripheralBatteryNotifierListenerTest, Basic) { |
| |
| // Level 50 at time 100, no low-battery notification. |
| ClockAdvance(base::TimeDelta::FromSeconds(100)); |
| SendBatteryUpdate(kTestBatteryPath, kTestDeviceName, 50); |
| EXPECT_EQ(1u, |
| battery_notifier_->battery_notifications_.count(kTestBatteryId)); |
| |
| const PeripheralBatteryNotifier::NotificationInfo& info = |
| battery_notifier_->battery_notifications_[kTestBatteryId]; |
| |
| EXPECT_EQ(base::nullopt, info.level); |
| EXPECT_EQ(GetTestingClock(), info.last_notification_timestamp); |
| EXPECT_FALSE( |
| message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); |
| |
| // Level 5 at time 110, low-battery notification. |
| ClockAdvance(base::TimeDelta::FromSeconds(10)); |
| SendBatteryUpdate( |
| kTestBatteryPath, kTestDeviceName, 5, |
| power_manager:: |
| PeripheralBatteryStatus_ChargeStatus_CHARGE_STATUS_DISCHARGING, |
| kBatteryEventUpdate); |
| EXPECT_EQ(5, info.level); |
| |
| EXPECT_EQ(GetTestingClock(), info.last_notification_timestamp); |
| EXPECT_TRUE( |
| message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); |
| |
| // Verify that the low-battery notification for stylus does not show up. |
| EXPECT_FALSE(message_center_->FindVisibleNotificationById( |
| PeripheralBatteryNotifier::kStylusNotificationId)); |
| |
| // Level -1 at time 115, cancel previous notification |
| ClockAdvance(base::TimeDelta::FromSeconds(5)); |
| SendBatteryUpdate(kTestBatteryPath, kTestDeviceName, -1); |
| EXPECT_EQ(base::nullopt, info.level); |
| EXPECT_EQ(GetTestingClock() - base::TimeDelta::FromSeconds(5), |
| info.last_notification_timestamp); |
| EXPECT_FALSE( |
| message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); |
| |
| // Level 50 at time 120, no low-battery notification. |
| ClockAdvance(base::TimeDelta::FromSeconds(5)); |
| SendBatteryUpdate(kTestBatteryPath, kTestDeviceName, 50); |
| EXPECT_EQ(base::nullopt, info.level); |
| EXPECT_EQ(GetTestingClock() - base::TimeDelta::FromSeconds(10), |
| info.last_notification_timestamp); |
| EXPECT_FALSE( |
| message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); |
| |
| // Level 5 at time 130, no low-battery notification (throttling). |
| ClockAdvance(base::TimeDelta::FromSeconds(10)); |
| SendBatteryUpdate(kTestBatteryPath, kTestDeviceName, 5); |
| EXPECT_EQ(5, info.level); |
| EXPECT_EQ(GetTestingClock() - base::TimeDelta::FromSeconds(20), |
| info.last_notification_timestamp); |
| EXPECT_FALSE( |
| message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); |
| } |
| |
| TEST_F(PeripheralBatteryNotifierListenerTest, InvalidBatteryInfo) { |
| const std::string invalid_path1 = "invalid-path"; |
| const std::string invalid_path2 = "/sys/class/power_supply/hid-battery"; |
| |
| SendBatteryUpdate(invalid_path1, kTestDeviceName, 10); |
| EXPECT_TRUE(battery_notifier_->battery_notifications_.empty()); |
| |
| SendBatteryUpdate(invalid_path2, kTestDeviceName, 10); |
| EXPECT_TRUE(battery_notifier_->battery_notifications_.empty()); |
| |
| SendBatteryUpdate(kTestBatteryPath, kTestDeviceName, -2); |
| EXPECT_TRUE(battery_notifier_->battery_notifications_.empty()); |
| |
| SendBatteryUpdate(kTestBatteryPath, kTestDeviceName, 101); |
| EXPECT_TRUE(battery_notifier_->battery_notifications_.empty()); |
| |
| SendBatteryUpdate(kTestBatteryPath, kTestDeviceName, -1); |
| EXPECT_TRUE(battery_notifier_->battery_notifications_.empty()); |
| } |
| |
| // Verify that for Bluetooth devices, the correct address gets stored in the |
| // BatteryInfo's bluetooth_address member, and for non-Bluetooth devices, that |
| // bluetooth_address member is empty. |
| TEST_F(PeripheralBatteryNotifierListenerTest, ExtractBluetoothAddress) { |
| const std::string bluetooth_path = |
| "/sys/class/power_supply/hid-A0:b1:C2:d3:E4:f5-battery"; |
| const std::string expected_bluetooth_address = "a0:b1:c2:d3:e4:f5"; |
| const std::string expected_bluetooth_id = |
| "battery_notification_bluetooth-a0:b1:c2:d3:e4:f5"; |
| const std::string non_bluetooth_path = |
| "/sys/class/power_supply/hid-notbluetooth-battery"; |
| |
| SendBatteryUpdate( |
| bluetooth_path, kTestDeviceName, 10, |
| power_manager:: |
| PeripheralBatteryStatus_ChargeStatus_CHARGE_STATUS_DISCHARGING, |
| kBluetoothBatteryUpdate); |
| SendBatteryUpdate( |
| non_bluetooth_path, kTestDeviceName, 10, |
| power_manager:: |
| PeripheralBatteryStatus_ChargeStatus_CHARGE_STATUS_DISCHARGING, |
| kBatteryPolledUpdate); |
| EXPECT_EQ(2u, battery_notifier_->battery_notifications_.size()); |
| } |
| |
| TEST_F(PeripheralBatteryNotifierListenerTest, DeviceRemove) { |
| SendBatteryUpdate(kTestBatteryPath, kTestDeviceName, 5); |
| EXPECT_EQ(1u, |
| battery_notifier_->battery_notifications_.count(kTestBatteryId)); |
| EXPECT_TRUE( |
| message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); |
| |
| battery_listener_->RemoveBluetoothBattery(kTestBatteryAddress); |
| EXPECT_FALSE( |
| message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); |
| } |
| |
| TEST_F(PeripheralBatteryNotifierListenerIncompleteDevicesTest, |
| StylusNotification) { |
| const std::string kTestStylusBatteryPath = |
| "/sys/class/power_supply/hid-AAAA:BBBB:CCCC.DDDD-battery"; |
| const std::string kTestStylusName = "test_stylus"; |
| |
| // Add an external stylus to our test device manager. |
| ui::TouchscreenDevice stylus(/*id=*/0, ui::INPUT_DEVICE_USB, kTestStylusName, |
| gfx::Size(), |
| /*touch_points=*/1, /*has_stylus=*/true); |
| stylus.sys_path = base::FilePath(kTestStylusBatteryPath); |
| |
| ui::DeviceDataManagerTestApi().SetTouchscreenDevices({stylus}); |
| |
| // Verify that when the battery level is 5, a stylus low battery notification |
| // is not shown due to input device list not being complete. Also check that |
| // a non stylus device low battery notification will not show up. |
| SendBatteryUpdate( |
| kTestStylusBatteryPath, kTestStylusName, 5, |
| power_manager:: |
| PeripheralBatteryStatus_ChargeStatus_CHARGE_STATUS_DISCHARGING, |
| kBatteryEventUpdate); |
| EXPECT_FALSE(message_center_->FindVisibleNotificationById( |
| PeripheralBatteryNotifier::kStylusNotificationId)); |
| EXPECT_FALSE( |
| message_center_->FindVisibleNotificationById(kTestBatteryAddress)); |
| |
| // Complete devices |
| ui::DeviceDataManagerTestApi().OnDeviceListsComplete(); |
| |
| // Verify that when the battery level is 5, a stylus low battery notification |
| // is now shown. Also check that a non stylus device low battery notification |
| // will still not show up. |
| SendBatteryUpdate( |
| kTestStylusBatteryPath, kTestStylusName, 5, |
| power_manager:: |
| PeripheralBatteryStatus_ChargeStatus_CHARGE_STATUS_DISCHARGING, |
| kBatteryEventUpdate); |
| EXPECT_TRUE(message_center_->FindVisibleNotificationById( |
| PeripheralBatteryNotifier::kStylusNotificationId)); |
| EXPECT_FALSE( |
| message_center_->FindVisibleNotificationById(kTestBatteryAddress)); |
| } |
| |
| TEST_F(PeripheralBatteryNotifierListenerTest, StylusNotification) { |
| const std::string kTestStylusBatteryPath = |
| "/sys/class/power_supply/hid-AAAA:BBBB:CCCC.DDDD-battery"; |
| const std::string kTestStylusName = "test_stylus"; |
| |
| // Add an external stylus to our test device manager. |
| ui::TouchscreenDevice stylus(/*id=*/0, ui::INPUT_DEVICE_USB, kTestStylusName, |
| gfx::Size(), |
| /*touch_points=*/1, /*has_stylus=*/true); |
| stylus.sys_path = base::FilePath(kTestStylusBatteryPath); |
| |
| ui::DeviceDataManagerTestApi().SetTouchscreenDevices({stylus}); |
| |
| // Verify that when the battery level is 50, no stylus low battery |
| // notification is shown. |
| SendBatteryUpdate(kTestStylusBatteryPath, kTestStylusName, 50); |
| EXPECT_FALSE(message_center_->FindVisibleNotificationById( |
| PeripheralBatteryNotifier::kStylusNotificationId)); |
| |
| // Verify that when the battery level is 5, a stylus low battery notification |
| // is shown. Also check that a non stylus device low battery notification will |
| // not show up. |
| SendBatteryUpdate(kTestStylusBatteryPath, kTestStylusName, 5); |
| EXPECT_TRUE(message_center_->FindVisibleNotificationById( |
| PeripheralBatteryNotifier::kStylusNotificationId)); |
| EXPECT_FALSE( |
| message_center_->FindVisibleNotificationById(kTestBatteryAddress)); |
| |
| // Verify that when the battery level is -1, the previous stylus low battery |
| // notification is cancelled. |
| SendBatteryUpdate(kTestStylusBatteryPath, kTestStylusName, -1); |
| EXPECT_FALSE(message_center_->FindVisibleNotificationById( |
| PeripheralBatteryNotifier::kStylusNotificationId)); |
| } |
| |
| TEST_F(PeripheralBatteryNotifierListenerTest, |
| Bluetooth_OnlyShowNotificationForLowBatteryLevels) { |
| // Should not create a notification for battery changes above the threshold. |
| battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), |
| mock_device_1_.get(), |
| /*new_battery_percentage=*/80); |
| EXPECT_EQ(0u, message_center_->NotificationCount()); |
| battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), |
| mock_device_1_.get(), |
| /*new_battery_percentage=*/100); |
| EXPECT_EQ(0u, message_center_->NotificationCount()); |
| |
| // Should trigger notification. |
| battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), |
| mock_device_1_.get(), |
| /*new_battery_percentage=*/10); |
| EXPECT_EQ(1u, message_center_->NotificationCount()); |
| message_center::Notification* notification = |
| message_center_->FindVisibleNotificationById( |
| kBluetoothDeviceNotificationId1); |
| EXPECT_EQ(mock_device_1_->GetNameForDisplay(), notification->title()); |
| EXPECT_EQ(10, ExtractBatteryPercentage(notification)); |
| } |
| |
| TEST_F(PeripheralBatteryNotifierListenerTest, |
| Bluetooth_CreatesANotificationForEachDevice) { |
| battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), |
| mock_device_1_.get(), |
| /*new_battery_percentage=*/5); |
| battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), |
| mock_device_2_.get(), |
| /*new_battery_percentage=*/0); |
| |
| // Verify 2 notifications were posted with the correct values. |
| EXPECT_EQ(2u, message_center_->NotificationCount()); |
| message_center::Notification* notification_1 = |
| message_center_->FindVisibleNotificationById( |
| kBluetoothDeviceNotificationId1); |
| message_center::Notification* notification_2 = |
| message_center_->FindVisibleNotificationById( |
| kBluetoothDeviceNotificationId2); |
| |
| EXPECT_TRUE(notification_1); |
| EXPECT_EQ(mock_device_1_->GetNameForDisplay(), notification_1->title()); |
| EXPECT_EQ(5, ExtractBatteryPercentage(notification_1)); |
| EXPECT_TRUE(notification_2); |
| EXPECT_EQ(mock_device_2_->GetNameForDisplay(), notification_2->title()); |
| EXPECT_EQ(0, ExtractBatteryPercentage(notification_2)); |
| } |
| |
| TEST_F(PeripheralBatteryNotifierListenerTest, |
| Bluetooth_RemovesNotificationForDisconnectedDevices) { |
| battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), |
| mock_device_1_.get(), |
| /*new_battery_percentage=*/5); |
| battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), |
| mock_device_2_.get(), |
| /*new_battery_percentage=*/0); |
| |
| // Verify 2 notifications were posted. |
| EXPECT_EQ(2u, message_center_->NotificationCount()); |
| |
| // Verify only the notification for device 1 gets removed. |
| battery_listener_->DeviceConnectedStateChanged(mock_adapter_.get(), |
| mock_device_1_.get(), false); |
| EXPECT_EQ(1u, message_center_->NotificationCount()); |
| EXPECT_TRUE(message_center_->FindVisibleNotificationById( |
| kBluetoothDeviceNotificationId2)); |
| |
| // Remove the second notification. |
| battery_listener_->DeviceRemoved(mock_adapter_.get(), mock_device_2_.get()); |
| EXPECT_EQ(0u, message_center_->NotificationCount()); |
| } |
| |
| TEST_F(PeripheralBatteryNotifierListenerTest, |
| Bluetooth_CancelNotificationForInvalidBatteryLevel) { |
| battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), |
| mock_device_1_.get(), |
| /*new_battery_percentage=*/1); |
| EXPECT_TRUE(message_center_->FindVisibleNotificationById( |
| kBluetoothDeviceNotificationId1)); |
| |
| // The notification should get canceled. |
| battery_listener_->DeviceBatteryChanged( |
| mock_adapter_.get(), mock_device_1_.get(), |
| /*new_battery_percentage=*/base::nullopt); |
| EXPECT_FALSE(message_center_->FindVisibleNotificationById( |
| kBluetoothDeviceNotificationId1)); |
| } |
| |
| // Don't post a notification if the battery level drops again under the |
| // threshold before kNotificationInterval is completed. |
| TEST_F(PeripheralBatteryNotifierListenerTest, |
| DontShowSecondNotificationWithinASmallTimeInterval) { |
| ClockAdvance(base::TimeDelta::FromSeconds(100)); |
| |
| // Post a notification. |
| battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), |
| mock_device_1_.get(), |
| /*new_battery_percentage=*/1); |
| EXPECT_TRUE(message_center_->FindVisibleNotificationById( |
| kBluetoothDeviceNotificationId1)); |
| |
| // Cancel the notification. |
| ClockAdvance(base::TimeDelta::FromSeconds(1)); |
| battery_listener_->DeviceBatteryChanged( |
| mock_adapter_.get(), mock_device_1_.get(), |
| /*new_battery_percentage=*/base::nullopt); |
| EXPECT_FALSE(message_center_->FindVisibleNotificationById( |
| kBluetoothDeviceNotificationId1)); |
| |
| // The battery level falls below the threshold after a short time period. No |
| // notification should get posted. |
| ClockAdvance(base::TimeDelta::FromSeconds(1)); |
| battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), |
| mock_device_1_.get(), |
| /*new_battery_percentage=*/1); |
| EXPECT_FALSE(message_center_->FindVisibleNotificationById( |
| kBluetoothDeviceNotificationId1)); |
| } |
| |
| // Post a notification if the battery is under threshold, then unknown level and |
| // then is again under the threshold after kNotificationInterval is completed. |
| TEST_F(PeripheralBatteryNotifierListenerTest, |
| PostNotificationIfBatteryGoesFromUnknownLevelToBelowThreshold) { |
| ClockAdvance(base::TimeDelta::FromSeconds(100)); |
| |
| // Post a notification. |
| battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), |
| mock_device_1_.get(), |
| /*new_battery_percentage=*/1); |
| EXPECT_TRUE(message_center_->FindVisibleNotificationById( |
| kBluetoothDeviceNotificationId1)); |
| |
| // Cancel the notification. |
| ClockAdvance(base::TimeDelta::FromSeconds(1)); |
| battery_listener_->DeviceBatteryChanged( |
| mock_adapter_.get(), mock_device_1_.get(), |
| /*new_battery_percentage=*/base::nullopt); |
| EXPECT_FALSE(message_center_->FindVisibleNotificationById( |
| kBluetoothDeviceNotificationId1)); |
| |
| // Post notification if we are out of the kNotificationInterval. |
| ClockAdvance(base::TimeDelta::FromSeconds(100)); |
| battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), |
| mock_device_1_.get(), |
| /*new_battery_percentage=*/1); |
| EXPECT_TRUE(message_center_->FindVisibleNotificationById( |
| kBluetoothDeviceNotificationId1)); |
| } |
| |
| // Don't Post another notification if the battery level keeps low and the user |
| // dismissed the previous notification. |
| TEST_F(PeripheralBatteryNotifierListenerTest, |
| DontRepostNotificationIfUserDismissedPreviousOne) { |
| ClockAdvance(base::TimeDelta::FromSeconds(100)); |
| |
| battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), |
| mock_device_1_.get(), |
| /*new_battery_percentage=*/5); |
| EXPECT_EQ(1u, message_center_->NotificationCount()); |
| |
| // Simulate the user clears the notification. |
| message_center_->RemoveAllNotifications( |
| /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL); |
| |
| // The battery level remains low, but shouldn't post a notification. |
| ClockAdvance(base::TimeDelta::FromSeconds(100)); |
| battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), |
| mock_device_1_.get(), |
| /*new_battery_percentage=*/3); |
| EXPECT_EQ(0u, message_center_->NotificationCount()); |
| } |
| |
| // If there is an existing notification and the battery level remains low, |
| // update its content. |
| TEST_F(PeripheralBatteryNotifierListenerTest, UpdateNotificationIfVisible) { |
| ClockAdvance(base::TimeDelta::FromSeconds(100)); |
| |
| battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), |
| mock_device_1_.get(), |
| /*new_battery_percentage=*/5); |
| EXPECT_EQ(1u, message_center_->NotificationCount()); |
| |
| // The battery level remains low, should update the notification. |
| ClockAdvance(base::TimeDelta::FromSeconds(100)); |
| battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), |
| mock_device_1_.get(), |
| /*new_battery_percentage=*/3); |
| |
| message_center::Notification* notification = |
| message_center_->FindVisibleNotificationById( |
| kBluetoothDeviceNotificationId1); |
| EXPECT_TRUE(notification); |
| EXPECT_EQ(mock_device_1_->GetNameForDisplay(), notification->title()); |
| EXPECT_EQ(3, ExtractBatteryPercentage(notification)); |
| } |
| |
| } // namespace ash |