This source file includes following definitions.
- IsBluetoothHIDBattery
- ExtractBluetoothAddress
- Display
- Error
- Close
- Click
- id
- GetRenderViewHost
- weakptr_factory_
- PeripheralBatteryStatusReceived
- DeviceChanged
- DeviceRemoved
- InitializeOnBluetoothReady
- RemoveBattery
- PostNotification
- CancelNotification
#include "chrome/browser/chromeos/power/peripheral_battery_observer.h"
#include <vector>
#include "ash/shell.h"
#include "base/bind.h"
#include "base/strings/string16.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "content/public/browser/browser_thread.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_device.h"
#include "grit/ash_strings.h"
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image.h"
namespace chromeos {
namespace {
const int kLowBatteryLevel = 15;
const int kNotificationIntervalSec = 60;
const char kNotificationOriginUrl[] = "chrome://peripheral-battery";
const char kHIDBatteryPathPrefix[] = "/sys/class/power_supply/hid-";
const char kHIDBatteryPathSuffix[] = "-battery";
bool IsBluetoothHIDBattery(const std::string& path) {
return StartsWithASCII(path, kHIDBatteryPathPrefix, false) &&
EndsWith(path, kHIDBatteryPathSuffix, false);
}
std::string ExtractBluetoothAddress(const std::string& path) {
int header_size = strlen(kHIDBatteryPathPrefix);
int end_size = strlen(kHIDBatteryPathSuffix);
int key_len = path.size() - header_size - end_size;
if (key_len <= 0)
return std::string();
std::string reverse_address = path.substr(header_size, key_len);
StringToLowerASCII(&reverse_address);
std::vector<std::string> result;
base::SplitString(reverse_address, ':', &result);
std::reverse(result.begin(), result.end());
std::string address = JoinString(result, ':');
return address;
}
class PeripheralBatteryNotificationDelegate : public NotificationDelegate {
public:
explicit PeripheralBatteryNotificationDelegate(const std::string& id)
: id_(id) {}
virtual void Display() OVERRIDE {}
virtual void Error() OVERRIDE {}
virtual void Close(bool by_user) OVERRIDE {}
virtual void Click() OVERRIDE {}
virtual std::string id() const OVERRIDE { return id_; }
virtual content::RenderViewHost* GetRenderViewHost() const OVERRIDE {
return NULL;
}
private:
virtual ~PeripheralBatteryNotificationDelegate() {}
const std::string id_;
DISALLOW_COPY_AND_ASSIGN(PeripheralBatteryNotificationDelegate);
};
}
PeripheralBatteryObserver::PeripheralBatteryObserver()
: testing_clock_(NULL),
weakptr_factory_(
new base::WeakPtrFactory<PeripheralBatteryObserver>(this)) {
DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
device::BluetoothAdapterFactory::GetAdapter(
base::Bind(&PeripheralBatteryObserver::InitializeOnBluetoothReady,
weakptr_factory_->GetWeakPtr()));
}
PeripheralBatteryObserver::~PeripheralBatteryObserver() {
if (bluetooth_adapter_.get())
bluetooth_adapter_->RemoveObserver(this);
DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
}
void PeripheralBatteryObserver::PeripheralBatteryStatusReceived(
const std::string& path,
const std::string& name,
int level) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
std::string address;
if (IsBluetoothHIDBattery(path)) {
address = ExtractBluetoothAddress(path);
} else {
LOG(ERROR) << "Unsupported battery path " << path;
return;
}
if (address.empty()) {
LOG(ERROR) << "No valid battery address at path " << path;
return;
}
if (level < -1 || level > 100) {
LOG(ERROR) << "Invalid battery level " << level
<< " for device " << name << " at path " << path;
return;
}
if (level == -1) {
CancelNotification(address);
return;
}
if (batteries_.find(address) == batteries_.end()) {
BatteryInfo battery(name, level, base::TimeTicks());
if (level <= kLowBatteryLevel) {
if (PostNotification(address, battery))
battery.last_notification_timestamp = testing_clock_ ?
testing_clock_->NowTicks() : base::TimeTicks::Now();
}
batteries_[address] = battery;
} else {
BatteryInfo* battery = &batteries_[address];
battery->name = name;
int old_level = battery->level;
battery->level = level;
if (old_level > kLowBatteryLevel && level <= kLowBatteryLevel) {
if (PostNotification(address, *battery))
battery->last_notification_timestamp = testing_clock_ ?
testing_clock_->NowTicks() : base::TimeTicks::Now();
}
}
}
void PeripheralBatteryObserver::DeviceChanged(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) {
if (!device->IsPaired())
RemoveBattery(device->GetAddress());
}
void PeripheralBatteryObserver::DeviceRemoved(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) {
RemoveBattery(device->GetAddress());
}
void PeripheralBatteryObserver::InitializeOnBluetoothReady(
scoped_refptr<device::BluetoothAdapter> adapter) {
bluetooth_adapter_ = adapter;
CHECK(bluetooth_adapter_.get());
bluetooth_adapter_->AddObserver(this);
}
void PeripheralBatteryObserver::RemoveBattery(const std::string& address) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
std::string address_lowercase = address;
StringToLowerASCII(&address_lowercase);
std::map<std::string, BatteryInfo>::iterator it =
batteries_.find(address_lowercase);
if (it != batteries_.end()) {
batteries_.erase(it);
CancelNotification(address_lowercase);
}
}
bool PeripheralBatteryObserver::PostNotification(const std::string& address,
const BatteryInfo& battery) {
base::TimeTicks now = testing_clock_ ? testing_clock_->NowTicks() :
base::TimeTicks::Now();
if (now - battery.last_notification_timestamp <
base::TimeDelta::FromSeconds(kNotificationIntervalSec))
return false;
NotificationUIManager* notification_manager =
g_browser_process->notification_ui_manager();
base::string16 string_text = l10n_util::GetStringFUTF16Int(
IDS_ASH_LOW_PERIPHERAL_BATTERY_NOTIFICATION_TEXT,
battery.level);
Notification notification(
GURL(kNotificationOriginUrl),
ui::ResourceBundle::GetSharedInstance().GetImageNamed(
IDR_NOTIFICATION_PERIPHERAL_BATTERY_LOW),
base::UTF8ToUTF16(battery.name),
string_text,
blink::WebTextDirectionDefault,
base::string16(),
base::UTF8ToUTF16(address),
new PeripheralBatteryNotificationDelegate(address));
notification_manager->Add(
notification,
ProfileManager::GetPrimaryUserProfile());
return true;
}
void PeripheralBatteryObserver::CancelNotification(const std::string& address) {
g_browser_process->notification_ui_manager()->CancelById(address);
}
}