1 // Copyright 2014 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 "content/browser/battery_status/battery_status_manager.h" 6 7 #include "base/memory/ref_counted.h" 8 #include "chromeos/dbus/dbus_thread_manager.h" 9 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h" 10 #include "chromeos/dbus/power_manager_client.h" 11 #include "content/public/browser/browser_thread.h" 12 #include "third_party/WebKit/public/platform/WebBatteryStatus.h" 13 14 namespace content { 15 16 namespace { 17 18 class PowerManagerObserver 19 : public chromeos::PowerManagerClient::Observer, 20 public base::RefCountedThreadSafe<PowerManagerObserver> { 21 public: 22 explicit PowerManagerObserver( 23 const BatteryStatusService::BatteryUpdateCallback& callback) 24 : callback_(callback), currently_listening_(false) {} 25 26 // Starts listening for updates. It is safe to call this on any thread. 27 void Start() { 28 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { 29 StartOnUI(); 30 } else { 31 BrowserThread::PostTask( 32 BrowserThread::UI, 33 FROM_HERE, 34 base::Bind(&PowerManagerObserver::StartOnUI, this)); 35 } 36 } 37 38 // Stops listening for updates. It is safe to call this on any thread. 39 void Stop() { 40 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { 41 StopOnUI(); 42 } else { 43 BrowserThread::PostTask( 44 BrowserThread::UI, 45 FROM_HERE, 46 base::Bind(&PowerManagerObserver::StopOnUI, this)); 47 } 48 } 49 50 private: 51 friend class base::RefCountedThreadSafe<PowerManagerObserver>; 52 53 virtual ~PowerManagerObserver() {} 54 55 bool IsBatteryPresent( 56 const power_manager::PowerSupplyProperties& proto) const { 57 return proto.battery_state() != 58 power_manager::PowerSupplyProperties_BatteryState_NOT_PRESENT; 59 } 60 61 bool IsUsbChargerConnected( 62 const power_manager::PowerSupplyProperties& proto) const { 63 return proto.external_power() == 64 power_manager::PowerSupplyProperties_ExternalPower_USB; 65 } 66 67 bool IsBatteryCharging( 68 const power_manager::PowerSupplyProperties& proto) const { 69 return proto.battery_state() != 70 power_manager::PowerSupplyProperties_BatteryState_DISCHARGING; 71 } 72 73 bool IsBatteryFull(const power_manager::PowerSupplyProperties& proto) const { 74 return proto.battery_state() == 75 power_manager::PowerSupplyProperties_BatteryState_FULL; 76 } 77 78 double GetBatteryLevel( 79 const power_manager::PowerSupplyProperties& proto) const { 80 const double kMaxBatteryLevelProto = 100.f; 81 return proto.battery_percent() / kMaxBatteryLevelProto; 82 } 83 84 void StartOnUI() { 85 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 86 if (currently_listening_) 87 return; 88 chromeos::PowerManagerClient* power_client = 89 chromeos::DBusThreadManager::Get()->GetPowerManagerClient(); 90 power_client->AddObserver(this); 91 power_client->RequestStatusUpdate(); 92 currently_listening_ = true; 93 } 94 95 void StopOnUI() { 96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 97 if (!currently_listening_) 98 return; 99 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver( 100 this); 101 currently_listening_ = false; 102 } 103 104 // chromeos::PowerManagerClient::Observer: 105 virtual void PowerChanged( 106 const power_manager::PowerSupplyProperties& proto) OVERRIDE { 107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 108 blink::WebBatteryStatus status; 109 // Use the default values if there is no battery in the system. 110 if (IsBatteryPresent(proto)) { 111 // The charging status is unreliable if a low power charger is connected 112 // (i.e. usb). 113 bool status_unreliable = IsUsbChargerConnected(proto); 114 // Battery time is unreliable if it is still being computed. 115 bool time_unreliable = 116 status_unreliable || proto.is_calculating_battery_time(); 117 118 // Set |charging| only if the status is reliable. Otherwise, keep the 119 // default (which is |true|). 120 if (!status_unreliable) 121 status.charging = IsBatteryCharging(proto); 122 123 // Set |chargingTime| to +infinity if the battery is discharging, or if 124 // the time is unreliable. Keep the default value (which is 0) if the 125 // battery is full. 126 if (time_unreliable || !status.charging) 127 status.chargingTime = std::numeric_limits<double>::infinity(); 128 else if (!IsBatteryFull(proto)) 129 status.chargingTime = proto.battery_time_to_full_sec(); 130 131 // Keep the default value for |dischargingTime| (which is +infinity) if 132 // the time is unreliable, or if the battery is charging. 133 if (!time_unreliable && !status.charging) 134 status.dischargingTime = proto.battery_time_to_empty_sec(); 135 136 status.level = GetBatteryLevel(proto); 137 } 138 callback_.Run(status); 139 } 140 141 BatteryStatusService::BatteryUpdateCallback callback_; 142 bool currently_listening_; 143 144 DISALLOW_COPY_AND_ASSIGN(PowerManagerObserver); 145 }; 146 147 class BatteryStatusManagerChromeOS 148 : public BatteryStatusManager, 149 public chromeos::PowerManagerClient::Observer { 150 public: 151 explicit BatteryStatusManagerChromeOS( 152 const BatteryStatusService::BatteryUpdateCallback& callback) 153 : observer_(new PowerManagerObserver(callback)) {} 154 155 virtual ~BatteryStatusManagerChromeOS() { observer_->Stop(); } 156 157 private: 158 // BatteryStatusManager: 159 virtual bool StartListeningBatteryChange() OVERRIDE { 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 161 observer_->Start(); 162 return true; 163 } 164 165 virtual void StopListeningBatteryChange() OVERRIDE { 166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 167 observer_->Stop(); 168 } 169 170 scoped_refptr<PowerManagerObserver> observer_; 171 172 DISALLOW_COPY_AND_ASSIGN(BatteryStatusManagerChromeOS); 173 }; 174 175 } // namespace 176 177 // static 178 scoped_ptr<BatteryStatusManager> BatteryStatusManager::Create( 179 const BatteryStatusService::BatteryUpdateCallback& callback) { 180 return scoped_ptr<BatteryStatusManager>( 181 new BatteryStatusManagerChromeOS(callback)); 182 } 183 184 } // namespace content 185