1// Copyright (c) 2011 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 "chrome/browser/chromeos/cros/power_library.h"
6
7#include "base/message_loop.h"
8#include "base/string_util.h"
9#include "chrome/browser/chromeos/cros/cros_library.h"
10#include "content/browser/browser_thread.h"
11#include "third_party/cros/chromeos_resume.h"
12
13namespace chromeos {
14
15class PowerLibraryImpl : public PowerLibrary {
16 public:
17  PowerLibraryImpl()
18      : power_status_connection_(NULL),
19        resume_status_connection_(NULL),
20        status_(chromeos::PowerStatus()) {
21    if (CrosLibrary::Get()->EnsureLoaded()) {
22      Init();
23    }
24  }
25
26  ~PowerLibraryImpl() {
27    if (power_status_connection_) {
28      chromeos::DisconnectPowerStatus(power_status_connection_);
29      power_status_connection_ = NULL;
30    }
31    if (resume_status_connection_) {
32      chromeos::DisconnectResume(resume_status_connection_);
33      resume_status_connection_ = NULL;
34    }
35  }
36
37  void AddObserver(Observer* observer) {
38    observers_.AddObserver(observer);
39  }
40
41  void RemoveObserver(Observer* observer) {
42    observers_.RemoveObserver(observer);
43  }
44
45  bool line_power_on() const {
46    return status_.line_power_on;
47  }
48
49  bool battery_is_present() const {
50    return status_.battery_is_present;
51  }
52
53  bool battery_fully_charged() const {
54    return status_.battery_state == chromeos::BATTERY_STATE_FULLY_CHARGED;
55  }
56
57  double battery_percentage() const {
58    return status_.battery_percentage;
59  }
60
61  base::TimeDelta battery_time_to_empty() const {
62    return base::TimeDelta::FromSeconds(status_.battery_time_to_empty);
63  }
64
65  base::TimeDelta battery_time_to_full() const {
66    return base::TimeDelta::FromSeconds(status_.battery_time_to_full);
67  }
68
69  virtual void EnableScreenLock(bool enable) {
70    if (!CrosLibrary::Get()->EnsureLoaded())
71      return;
72
73    // Make sure we run on FILE thread becuase chromeos::EnableScreenLock
74    // would write power manager config file to disk.
75    if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
76      BrowserThread::PostTask(
77          BrowserThread::FILE, FROM_HERE,
78          NewRunnableMethod(this, &PowerLibraryImpl::EnableScreenLock, enable));
79      return;
80    }
81
82    chromeos::EnableScreenLock(enable);
83  }
84
85  virtual void RequestRestart() {
86    if (!CrosLibrary::Get()->EnsureLoaded())
87      return;
88    chromeos::RequestRestart();
89  }
90
91  virtual void RequestShutdown() {
92    if (!CrosLibrary::Get()->EnsureLoaded())
93      return;
94    chromeos::RequestShutdown();
95  }
96
97 private:
98  static void PowerStatusChangedHandler(void* object,
99      const chromeos::PowerStatus& status) {
100    PowerLibraryImpl* power = static_cast<PowerLibraryImpl*>(object);
101    power->UpdatePowerStatus(status);
102  }
103
104  static void SystemResumedHandler(void* object) {
105    PowerLibraryImpl* power = static_cast<PowerLibraryImpl*>(object);
106    power->SystemResumed();
107  }
108
109  void Init() {
110    power_status_connection_ = chromeos::MonitorPowerStatus(
111        &PowerStatusChangedHandler, this);
112    resume_status_connection_ =
113        chromeos::MonitorResume(&SystemResumedHandler, this);
114  }
115
116  void UpdatePowerStatus(const chromeos::PowerStatus& status) {
117    // Make sure we run on UI thread.
118    if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
119      BrowserThread::PostTask(
120          BrowserThread::UI, FROM_HERE,
121          NewRunnableMethod(
122              this, &PowerLibraryImpl::UpdatePowerStatus, status));
123      return;
124    }
125
126    DVLOG(1) << "Power lpo=" << status.line_power_on
127             << " sta=" << status.battery_state
128             << " per=" << status.battery_percentage
129             << " tte=" << status.battery_time_to_empty
130             << " ttf=" << status.battery_time_to_full;
131    status_ = status;
132    FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(this));
133  }
134
135  void SystemResumed() {
136    // Make sure we run on the UI thread.
137    if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
138      BrowserThread::PostTask(
139          BrowserThread::UI, FROM_HERE,
140          NewRunnableMethod(this, &PowerLibraryImpl::SystemResumed));
141      return;
142    }
143
144    FOR_EACH_OBSERVER(Observer, observers_, SystemResumed());
145  }
146
147  ObserverList<Observer> observers_;
148
149  // A reference to the battery power api, to allow callbacks when the battery
150  // status changes.
151  chromeos::PowerStatusConnection power_status_connection_;
152
153  // A reference to the resume alerts.
154  chromeos::ResumeConnection resume_status_connection_;
155
156  // The latest power status.
157  chromeos::PowerStatus status_;
158
159  DISALLOW_COPY_AND_ASSIGN(PowerLibraryImpl);
160};
161
162class PowerLibraryStubImpl : public PowerLibrary {
163 public:
164  PowerLibraryStubImpl() {}
165  ~PowerLibraryStubImpl() {}
166  void AddObserver(Observer* observer) {}
167  void RemoveObserver(Observer* observer) {}
168  bool line_power_on() const { return false; }
169  bool battery_is_present() const { return true; }
170  bool battery_fully_charged() const { return false; }
171  double battery_percentage() const { return 50.0; }
172  base::TimeDelta battery_time_to_empty() const {
173    return base::TimeDelta::FromSeconds(10 * 60);
174  }
175  base::TimeDelta battery_time_to_full() const {
176    return base::TimeDelta::FromSeconds(0);
177  }
178  virtual void EnableScreenLock(bool enable) {}
179  virtual void RequestRestart() {}
180  virtual void RequestShutdown() {}
181};
182
183// static
184PowerLibrary* PowerLibrary::GetImpl(bool stub) {
185  if (stub)
186    return new PowerLibraryStubImpl();
187  else
188    return new PowerLibraryImpl();
189}
190
191}  // namespace chromeos
192
193// Allows InvokeLater without adding refcounting. This class is a Singleton and
194// won't be deleted until it's last InvokeLater is run.
195DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::PowerLibraryImpl);
196