1 // Copyright (c) 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 #ifndef ASH_SYSTEM_POWER_PERIPHERAL_BATTERY_NOTIFIER_H_
6 #define ASH_SYSTEM_POWER_PERIPHERAL_BATTERY_NOTIFIER_H_
7 
8 #include <cstdint>
9 #include <map>
10 
11 #include "ash/ash_export.h"
12 #include "base/compiler_specific.h"
13 #include "base/gtest_prod_util.h"
14 #include "base/macros.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/optional.h"
17 #include "base/time/tick_clock.h"
18 #include "chromeos/dbus/power/power_manager_client.h"
19 #include "device/bluetooth/bluetooth_adapter.h"
20 
21 namespace ash {
22 
23 class BluetoothDevice;
24 class PeripheralBatteryNotifierTest;
25 
26 // This class listens for peripheral device battery status and shows
27 // notifications for low battery conditions.
28 class ASH_EXPORT PeripheralBatteryNotifier
29     : public chromeos::PowerManagerClient::Observer,
30       public device::BluetoothAdapter::Observer {
31  public:
32   static const char kStylusNotificationId[];
33 
34   // This class registers/unregisters itself as an observer in ctor/dtor.
35   PeripheralBatteryNotifier();
36   ~PeripheralBatteryNotifier() override;
37 
38 
39   // chromeos::PowerManagerClient::Observer:
40   void PeripheralBatteryStatusReceived(const std::string& path,
41                                        const std::string& name,
42                                        int level) override;
43 
44   // device::BluetoothAdapter::Observer:
45   void DeviceBatteryChanged(
46       device::BluetoothAdapter* adapter,
47       device::BluetoothDevice* device,
48       base::Optional<uint8_t> new_battery_percentage) override;
49   void DeviceConnectedStateChanged(device::BluetoothAdapter* adapter,
50                                    device::BluetoothDevice* device,
51                                    bool is_now_connected) override;
52   void DeviceRemoved(device::BluetoothAdapter* adapter,
53                      device::BluetoothDevice* device) override;
54 
55  private:
56   friend class PeripheralBatteryNotifierTest;
57   FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryNotifierTest, Basic);
58   FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryNotifierTest, InvalidBatteryInfo);
59   FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryNotifierTest,
60                            ExtractBluetoothAddress);
61   FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryNotifierTest, DeviceRemove);
62 
63   struct BatteryInfo {
64     BatteryInfo();
65     BatteryInfo(const base::string16& name,
66                 base::Optional<uint8_t> level,
67                 base::TimeTicks last_notification_timestamp,
68                 bool is_stylus,
69                 const std::string& bluetooth_address);
70     ~BatteryInfo();
71     BatteryInfo(const BatteryInfo& info);
72 
73     // Human readable name for the device. It is changeable.
74     base::string16 name;
75     // Battery level within range [0, 100].
76     base::Optional<uint8_t> level;
77     base::TimeTicks last_notification_timestamp;
78     bool is_stylus = false;
79     // Peripheral's Bluetooth address. Empty for non-Bluetooth devices.
80     std::string bluetooth_address;
81   };
82 
83   void InitializeOnBluetoothReady(
84       scoped_refptr<device::BluetoothAdapter> adapter);
85 
86   // Removes the Bluetooth battery with address |bluetooth_address|, as well as
87   // the associated notification. Called when a bluetooth device has been
88   // changed or removed.
89   void RemoveBluetoothBattery(const std::string& bluetooth_address);
90 
91   // Updates the battery information of the peripheral with the corresponding
92   // |map_key|, and calls to post a notification if the battery level is under
93   // the threshold.
94   void UpdateBattery(const std::string& map_key,
95                      const BatteryInfo& battery_info);
96 
97   // Updates the battery percentage in the corresponding notification.
98   void UpdateBatteryNotificationIfVisible(const std::string& map_key,
99                                           const BatteryInfo& battery);
100 
101   // Calls to display a notification only if kNotificationInterval seconds have
102   // passed since the last notification showed, avoiding the case where the
103   // battery level oscillates around the threshold level.
104   void ShowNotification(const std::string& map_key, const BatteryInfo& battery);
105 
106   // Posts a low battery notification with id as |map_key|. If a notification
107   // with the same id exists, its content gets updated.
108   void ShowOrUpdateNotification(const std::string& map_key,
109                                 const BatteryInfo& battery);
110 
111   void CancelNotification(const std::string& map_key);
112 
113   // Record of existing battery information. For Bluetooth Devices, the key is
114   // kBluetoothDeviceIdPrefix + the device's address. For HID devices, the key
115   // is the device path. If a device uses HID over Bluetooth, it is indexed as a
116   // Bluetooth device.
117   std::map<std::string, BatteryInfo> batteries_;
118 
119   // PeripheralBatteryNotifier is an observer of |bluetooth_adapter_| for
120   // bluetooth device change/remove events.
121   scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_;
122 
123   const base::TickClock* clock_;
124 
125   std::unique_ptr<base::WeakPtrFactory<PeripheralBatteryNotifier>>
126       weakptr_factory_;
127 
128   DISALLOW_COPY_AND_ASSIGN(PeripheralBatteryNotifier);
129 };
130 
131 }  // namespace ash
132 
133 #endif  // ASH_SYSTEM_POWER_PERIPHERAL_BATTERY_NOTIFIER_H_
134