Home | History | Annotate | Download | only in battery_status
      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