blob: 420cf568d877f1cc697d19f6b59868849e955522 [file] [log] [blame]
// Copyright 2013 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_notifier.h"
#include <memory>
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "base/macros.h"
#include "base/test/simple_test_tick_clock.h"
#include "services/ws/public/cpp/input_devices/input_device_client_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"
namespace {
const char kTestBatteryPath[] =
"/sys/class/power_supply/hid-AA:BB:CC:DD:EE:FF-battery";
const char kTestBatteryAddress[] = "ff:ee:dd:cc:bb:aa";
const char kTestDeviceName[] = "test device";
} // namespace
namespace ash {
class PeripheralBatteryNotifierTest : public ash::AshTestBase {
public:
PeripheralBatteryNotifierTest() = default;
~PeripheralBatteryNotifierTest() override = default;
void SetUp() override {
ash::AshTestBase::SetUp();
observer_ = std::make_unique<PeripheralBatteryNotifier>();
}
void TearDown() override {
observer_.reset();
ash::AshTestBase::TearDown();
}
protected:
std::unique_ptr<PeripheralBatteryNotifier> observer_;
private:
DISALLOW_COPY_AND_ASSIGN(PeripheralBatteryNotifierTest);
};
TEST_F(PeripheralBatteryNotifierTest, Basic) {
base::SimpleTestTickClock clock;
observer_->set_testing_clock(&clock);
message_center::MessageCenter* message_center =
message_center::MessageCenter::Get();
// Level 50 at time 100, no low-battery notification.
clock.Advance(base::TimeDelta::FromSeconds(100));
observer_->PeripheralBatteryStatusReceived(kTestBatteryPath, kTestDeviceName,
50);
EXPECT_EQ(1u, observer_->batteries_.count(kTestBatteryPath));
const PeripheralBatteryNotifier::BatteryInfo& info =
observer_->batteries_[kTestBatteryPath];
EXPECT_EQ(kTestDeviceName, info.name);
EXPECT_EQ(50, info.level);
EXPECT_EQ(base::TimeTicks(), info.last_notification_timestamp);
EXPECT_EQ(kTestBatteryAddress, info.bluetooth_address);
EXPECT_TRUE(message_center->FindVisibleNotificationById(kTestBatteryPath) ==
nullptr);
// Level 5 at time 110, low-battery notification.
clock.Advance(base::TimeDelta::FromSeconds(10));
observer_->PeripheralBatteryStatusReceived(kTestBatteryPath, kTestDeviceName,
5);
EXPECT_EQ(5, info.level);
EXPECT_EQ(clock.NowTicks(), info.last_notification_timestamp);
EXPECT_TRUE(message_center->FindVisibleNotificationById(kTestBatteryPath) !=
nullptr);
// Verify that the low-battery notification for stylus does not show up.
EXPECT_FALSE(message_center->FindVisibleNotificationById(
PeripheralBatteryNotifier::kStylusNotificationId) !=
nullptr);
// Level -1 at time 115, cancel previous notification
clock.Advance(base::TimeDelta::FromSeconds(5));
observer_->PeripheralBatteryStatusReceived(kTestBatteryPath, kTestDeviceName,
-1);
EXPECT_EQ(5, info.level);
EXPECT_EQ(clock.NowTicks() - base::TimeDelta::FromSeconds(5),
info.last_notification_timestamp);
EXPECT_TRUE(message_center->FindVisibleNotificationById(kTestBatteryPath) ==
nullptr);
// Level 50 at time 120, no low-battery notification.
clock.Advance(base::TimeDelta::FromSeconds(5));
observer_->PeripheralBatteryStatusReceived(kTestBatteryPath, kTestDeviceName,
50);
EXPECT_EQ(50, info.level);
EXPECT_EQ(clock.NowTicks() - base::TimeDelta::FromSeconds(10),
info.last_notification_timestamp);
EXPECT_TRUE(message_center->FindVisibleNotificationById(kTestBatteryPath) ==
nullptr);
// Level 5 at time 130, no low-battery notification (throttling).
clock.Advance(base::TimeDelta::FromSeconds(10));
observer_->PeripheralBatteryStatusReceived(kTestBatteryPath, kTestDeviceName,
5);
EXPECT_EQ(5, info.level);
EXPECT_EQ(clock.NowTicks() - base::TimeDelta::FromSeconds(20),
info.last_notification_timestamp);
EXPECT_TRUE(message_center->FindVisibleNotificationById(kTestBatteryPath) ==
nullptr);
}
TEST_F(PeripheralBatteryNotifierTest, InvalidBatteryInfo) {
const std::string invalid_path1 = "invalid-path";
const std::string invalid_path2 = "/sys/class/power_supply/hid-battery";
observer_->PeripheralBatteryStatusReceived(invalid_path1, kTestDeviceName,
10);
EXPECT_TRUE(observer_->batteries_.empty());
observer_->PeripheralBatteryStatusReceived(invalid_path2, kTestDeviceName,
10);
EXPECT_TRUE(observer_->batteries_.empty());
observer_->PeripheralBatteryStatusReceived(kTestBatteryPath, kTestDeviceName,
-2);
EXPECT_TRUE(observer_->batteries_.empty());
observer_->PeripheralBatteryStatusReceived(kTestBatteryPath, kTestDeviceName,
101);
EXPECT_TRUE(observer_->batteries_.empty());
observer_->PeripheralBatteryStatusReceived(kTestBatteryPath, kTestDeviceName,
-1);
EXPECT_TRUE(observer_->batteries_.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(PeripheralBatteryNotifierTest, ExtractBluetoothAddress) {
const std::string bluetooth_path =
"/sys/class/power_supply/hid-A0:b1:C2:d3:E4:f5-battery";
const std::string expected_bluetooth_address = "f5:e4:d3:c2:b1:a0";
const std::string non_bluetooth_path =
"/sys/class/power_supply/hid-notbluetooth-battery";
observer_->PeripheralBatteryStatusReceived(bluetooth_path, kTestDeviceName,
10);
observer_->PeripheralBatteryStatusReceived(non_bluetooth_path,
kTestDeviceName, 10);
EXPECT_EQ(2u, observer_->batteries_.size());
const PeripheralBatteryNotifier::BatteryInfo& bluetooth_device_info =
observer_->batteries_[bluetooth_path];
EXPECT_EQ(expected_bluetooth_address,
bluetooth_device_info.bluetooth_address);
const PeripheralBatteryNotifier::BatteryInfo& non_bluetooth_device_info =
observer_->batteries_[non_bluetooth_path];
EXPECT_TRUE(non_bluetooth_device_info.bluetooth_address.empty());
}
// TODO(crbug.com/765794): Flaky on ash_unittests with mus.
TEST_F(PeripheralBatteryNotifierTest, DISABLED_DeviceRemove) {
message_center::MessageCenter* message_center =
message_center::MessageCenter::Get();
observer_->PeripheralBatteryStatusReceived(kTestBatteryPath, kTestDeviceName,
5);
EXPECT_EQ(1u, observer_->batteries_.count(kTestBatteryPath));
EXPECT_TRUE(message_center->FindVisibleNotificationById(kTestBatteryPath) !=
nullptr);
observer_->RemoveBluetoothBattery(kTestBatteryAddress);
EXPECT_TRUE(message_center->FindVisibleNotificationById(kTestBatteryPath) ==
nullptr);
}
// TODO(crbug.com/765794): Flaky on ash_unittests with mus.
TEST_F(PeripheralBatteryNotifierTest, DISABLED_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(0 /* id */, ui::INPUT_DEVICE_USB,
kTestStylusName, gfx::Size(),
1 /* touch_points */, true /* has_stylus */);
stylus.sys_path = base::FilePath(kTestStylusBatteryPath);
ws::InputDeviceClientTestApi().SetTouchscreenDevices({stylus});
message_center::MessageCenter* message_center =
message_center::MessageCenter::Get();
// Verify that when the battery level is 50, no stylus low battery
// notification is shown.
observer_->PeripheralBatteryStatusReceived(kTestStylusBatteryPath,
kTestStylusName, 50);
EXPECT_TRUE(message_center->FindVisibleNotificationById(
PeripheralBatteryNotifier::kStylusNotificationId) == nullptr);
// 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.
observer_->PeripheralBatteryStatusReceived(kTestStylusBatteryPath,
kTestStylusName, 5);
EXPECT_TRUE(message_center->FindVisibleNotificationById(
PeripheralBatteryNotifier::kStylusNotificationId) != nullptr);
EXPECT_TRUE(message_center->FindVisibleNotificationById(
kTestBatteryAddress) == nullptr);
// Verify that when the battery level is -1, the previous stylus low battery
// notification is cancelled.
observer_->PeripheralBatteryStatusReceived(kTestStylusBatteryPath,
kTestStylusName, -1);
EXPECT_TRUE(message_center->FindVisibleNotificationById(
PeripheralBatteryNotifier::kStylusNotificationId) == nullptr);
}
} // namespace ash