Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(453)

Side by Side Diff: chrome/browser/chromeos/power/peripheral_battery_observer.cc

Issue 13638018: Add PeripheralBatteryObserver (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: browser tests added Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 #include <vector>
6
7 #include "chrome/browser/chromeos/power/peripheral_battery_observer.h"
8
9 #include "ash/shell.h"
10 #include "base/bind.h"
11 #include "base/string16.h"
12 #include "base/stringprintf.h"
13 #include "base/strings/string_split.h"
14 #include "base/utf_string_conversions.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/notifications/notification.h"
17 #include "chrome/browser/notifications/notification_ui_manager.h"
18 #include "chrome/browser/profiles/profile_manager.h"
19 #include "chromeos/dbus/dbus_thread_manager.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "device/bluetooth/bluetooth_adapter_factory.h"
22 #include "device/bluetooth/bluetooth_device.h"
23 #include "grit/ash_strings.h"
24 #include "grit/theme_resources.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/base/resource/resource_bundle.h"
27 #include "ui/gfx/image/image.h"
28
29 namespace chromeos {
30
31 namespace {
32
33 // When a peripheral device's battery level is <= kLowBatteryLevel, consider
34 // it to be in low battery condition.
35 const int kLowBatteryLevel = 15;
36
37 // Don't show 2 low battery notification within |kNotificationIntervalSec|
38 // seconds.
39 const int kNotificationIntervalSec = 60;
40
41 // HID Bluetooth device's battery sysfs entry path looks like
42 // "/sys/class/power_supply/hid-AA:BB:CC:DD:EE:FF-battery".
43 // Here the bluetooth address is showed in reverse order and its true
44 // address "FF:EE:DD:CC:BB:AA".
45 const char kHIDBatteryPathPrefix[] = "/sys/class/power_supply/hid-";
46 const char kHIDBatteryPathSuffix[] = "-battery";
47
48 bool IsBluetoothHIDBattery(const std::string& path) {
49 return StartsWithASCII(path, kHIDBatteryPathPrefix, false) &&
50 EndsWith(path, kHIDBatteryPathSuffix, false);
51 }
52
53 std::string ExtractBluetoothAddress(const std::string& path) {
54 int header_size = strlen(kHIDBatteryPathPrefix);
55 int end_size = strlen(kHIDBatteryPathSuffix);
56 int key_len = path.size() - header_size - end_size;
57 if (key_len <= 0)
58 return std::string();
59 std::string reverse_address = path.substr(header_size, key_len);
60 StringToLowerASCII(&reverse_address);
61 std::vector<std::string> result;
62 base::SplitString(reverse_address, ':', &result);
63 std::reverse(result.begin(), result.end());
64 std::string address = JoinString(result, ':');
65 return address;
66 }
67
68 class PeripheralBatteryNotificationDelegate : public NotificationDelegate {
69 public:
70 explicit PeripheralBatteryNotificationDelegate(const std::string& id)
71 : id_(id) {}
72
73 // Overridden from NotificationDelegate:
74 virtual void Display() OVERRIDE {}
75 virtual void Error() OVERRIDE {}
76 virtual void Close(bool by_user) OVERRIDE {}
77 virtual void Click() OVERRIDE {}
78 virtual std::string id() const OVERRIDE { return id_; }
79 // A NULL return value prevents loading image from URL. It is OK since our
80 // implementation loads image from system resource bundle.
81 virtual content::RenderViewHost* GetRenderViewHost() const OVERRIDE {
82 return NULL;
83 }
84
85 private:
86 const std::string id_;
87
88 DISALLOW_COPY_AND_ASSIGN(PeripheralBatteryNotificationDelegate);
89 };
90
91 } // namespace
92
93 PeripheralBatteryObserver::PeripheralBatteryObserver()
94 : testing_clock_(NULL),
95 weakptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(
96 new base::WeakPtrFactory<PeripheralBatteryObserver>(this))) {
97 DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
98 device::BluetoothAdapterFactory::GetAdapter(
99 base::Bind(&PeripheralBatteryObserver::InitializeOnBluetoothReady,
100 weakptr_factory_->GetWeakPtr()));
101 }
102
103 PeripheralBatteryObserver::~PeripheralBatteryObserver() {
104 if (bluetooth_adapter_.get())
105 bluetooth_adapter_->RemoveObserver(this);
106 DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
107 }
108
109 void PeripheralBatteryObserver::PeripheralBatteryStatusReceived(
110 const std::string& path,
111 const std::string& name,
112 int level) {
113 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
114 std::string address;
115 if (IsBluetoothHIDBattery(path)) {
116 // For HID bluetooh device, device address is used as key to index
Daniel Erat 2013/04/10 12:58:21 fix indenting: this should be two spaces beyond th
Yufeng Shen (Slow to review) 2013/04/10 18:13:46 Done.
117 // BatteryInfo.
118 address = ExtractBluetoothAddress(path);
119 } else {
120 LOG(ERROR) << "Unsupported battery path " << path;
121 return;
122 }
123
124 if (address == std::string()) {
Daniel Erat 2013/04/10 12:58:21 if (address.empty()) {
Yufeng Shen (Slow to review) 2013/04/10 18:13:46 Done.
125 LOG(ERROR) << "No valid battery address at path " << path;
126 return;
127 }
128
129 if (level < -1 || level > 100) {
130 LOG(ERROR) << "Invalid battery level " << level
131 << " for device " << name << " at path " << path;
132 return;
133 }
134 // If unknown battery level received, cancel any existing notification.
135 if (level == -1) {
136 CancelNotification(address);
137 return;
138 }
139
140 // Post the notification in 2 cases:
141 // 1. It's the first time the battery level is received, and it is
142 // below kLowBatteryLevel.
143 // 2. The battery level is in record and it drops below kLowBatteryLevel.
144 if (batteries_.find(address) == batteries_.end()) {
145 BatteryInfo battery(name, level, base::TimeTicks());
146 if (level <= kLowBatteryLevel) {
147 if (PostNotification(address, battery))
148 battery.last_notification_timestamp = testing_clock_ ?
149 testing_clock_->NowTicks() : base::TimeTicks::Now();
150 }
151 batteries_[address] = battery;
152 } else {
153 BatteryInfo* battery = &batteries_[address];
154 battery->name = name;
155 int old_level = battery->level;
156 battery->level = level;
157 if (old_level > kLowBatteryLevel && level <= kLowBatteryLevel) {
158 if (PostNotification(address, *battery))
159 battery->last_notification_timestamp = testing_clock_ ?
160 testing_clock_->NowTicks() : base::TimeTicks::Now();
161 }
162 }
163 }
164
165 void PeripheralBatteryObserver::DeviceChanged(device::BluetoothAdapter* adapter,
166 device::BluetoothDevice* device) {
167 if (!device->IsPaired())
168 RemoveBattery(device->GetAddress());
169 }
170
171 void PeripheralBatteryObserver::DeviceRemoved(device::BluetoothAdapter* adapter,
172 device::BluetoothDevice* device) {
173 RemoveBattery(device->GetAddress());
174 }
175
176 void PeripheralBatteryObserver::InitializeOnBluetoothReady(
177 scoped_refptr<device::BluetoothAdapter> adapter) {
178 bluetooth_adapter_ = adapter;
179 CHECK(bluetooth_adapter_);
180 bluetooth_adapter_->AddObserver(this);
181 }
182
183 void PeripheralBatteryObserver::RemoveBattery(const std::string& address) {
184 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
185 std::string address_lowercase = address;
186 StringToLowerASCII(&address_lowercase);
187 std::map<std::string, BatteryInfo>::iterator it =
188 batteries_.find(address_lowercase);
189 if (it != batteries_.end()) {
190 batteries_.erase(it);
191 CancelNotification(address_lowercase);
192 }
193 }
194
195 bool PeripheralBatteryObserver::PostNotification(const std::string& address,
196 const BatteryInfo& battery) {
197 // Only post notification if kNotificationInterval seconds have passed since
198 // last notification showed, avoiding the case where the battery level
199 // oscillates around the threshold level.
200 base::TimeTicks now = testing_clock_ ? testing_clock_->NowTicks() :
201 base::TimeTicks::Now();
202 if (now - battery.last_notification_timestamp <
203 base::TimeDelta::FromSeconds(kNotificationIntervalSec))
204 return false;
205
206 NotificationUIManager* notification_manager =
207 g_browser_process->notification_ui_manager();
208
209 base::string16 string_text = l10n_util::GetStringFUTF16Int(
210 IDS_ASH_LOW_PERIPHERAL_BATTERY_NOTIFICATION_TEXT,
211 battery.level);
212
213 Notification notification(
214 // TODO(mukai): add SYSTEM priority and use here.
215 GURL(),
216 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
217 IDR_NOTIFICATION_PERIPHERAL_BATTERY_LOW),
218 UTF8ToUTF16(battery.name),
219 string_text,
220 WebKit::WebTextDirectionDefault,
221 string16(),
222 UTF8ToUTF16(address),
223 new PeripheralBatteryNotificationDelegate(address));
224
225 notification_manager->Add(notification,
226 ProfileManager::GetDefaultProfileOrOffTheRecord());
227
228 return true;
229 }
230
231 void PeripheralBatteryObserver::CancelNotification(const std::string& id) {
Daniel Erat 2013/04/10 12:58:21 rename 'id' to 'address' here to match the header
Yufeng Shen (Slow to review) 2013/04/10 18:13:46 Done.
232 g_browser_process->notification_ui_manager()->CancelById(id);
233 }
234
235 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698