- add sources.
[platform/framework/web/crosswalk.git] / src / device / bluetooth / bluetooth_adapter_chromeos.cc
1 // Copyright 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 "device/bluetooth/bluetooth_adapter_chromeos.h"
6
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/metrics/histogram.h"
12 #include "base/sys_info.h"
13 #include "chromeos/dbus/bluetooth_adapter_client.h"
14 #include "chromeos/dbus/bluetooth_device_client.h"
15 #include "chromeos/dbus/bluetooth_input_client.h"
16 #include "chromeos/dbus/dbus_thread_manager.h"
17 #include "device/bluetooth/bluetooth_device.h"
18 #include "device/bluetooth/bluetooth_device_chromeos.h"
19
20 using device::BluetoothAdapter;
21 using device::BluetoothDevice;
22
23 namespace chromeos {
24
25 BluetoothAdapterChromeOS::BluetoothAdapterChromeOS()
26     : weak_ptr_factory_(this) {
27   DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this);
28   DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this);
29   DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this);
30
31   std::vector<dbus::ObjectPath> object_paths =
32       DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters();
33
34   if (!object_paths.empty()) {
35     VLOG(1) << object_paths.size() << " Bluetooth adapter(s) available.";
36     SetAdapter(object_paths[0]);
37   }
38 }
39
40 BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() {
41   DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this);
42   DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this);
43   DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this);
44 }
45
46 void BluetoothAdapterChromeOS::AddObserver(
47     BluetoothAdapter::Observer* observer) {
48   DCHECK(observer);
49   observers_.AddObserver(observer);
50 }
51
52 void BluetoothAdapterChromeOS::RemoveObserver(
53     BluetoothAdapter::Observer* observer) {
54   DCHECK(observer);
55   observers_.RemoveObserver(observer);
56 }
57
58 std::string BluetoothAdapterChromeOS::GetAddress() const {
59   if (!IsPresent())
60     return std::string();
61
62   BluetoothAdapterClient::Properties* properties =
63       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
64           GetProperties(object_path_);
65   DCHECK(properties);
66
67   return properties->address.value();
68 }
69
70 std::string BluetoothAdapterChromeOS::GetName() const {
71   if (!IsPresent())
72     return std::string();
73
74   BluetoothAdapterClient::Properties* properties =
75       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
76           GetProperties(object_path_);
77   DCHECK(properties);
78
79   return properties->alias.value();
80 }
81
82 bool BluetoothAdapterChromeOS::IsInitialized() const {
83   return true;
84 }
85
86 bool BluetoothAdapterChromeOS::IsPresent() const {
87   return !object_path_.value().empty();
88 }
89
90 bool BluetoothAdapterChromeOS::IsPowered() const {
91   if (!IsPresent())
92     return false;
93
94   BluetoothAdapterClient::Properties* properties =
95       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
96           GetProperties(object_path_);
97
98   return properties->powered.value();
99 }
100
101 void BluetoothAdapterChromeOS::SetPowered(
102     bool powered,
103     const base::Closure& callback,
104     const ErrorCallback& error_callback) {
105   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
106       GetProperties(object_path_)->powered.Set(
107           powered,
108           base::Bind(&BluetoothAdapterChromeOS::OnSetPowered,
109                      weak_ptr_factory_.GetWeakPtr(),
110                      callback,
111                      error_callback));
112 }
113
114 bool BluetoothAdapterChromeOS::IsDiscovering() const {
115   if (!IsPresent())
116     return false;
117
118   BluetoothAdapterClient::Properties* properties =
119       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
120           GetProperties(object_path_);
121
122   return properties->discovering.value();
123 }
124
125 void BluetoothAdapterChromeOS::StartDiscovering(
126     const base::Closure& callback,
127     const ErrorCallback& error_callback) {
128   // BlueZ counts discovery sessions, and permits multiple sessions for a
129   // single connection, so issue a StartDiscovery() call for every use
130   // within Chromium for the right behavior.
131   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
132       StartDiscovery(
133           object_path_,
134           base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery,
135                      weak_ptr_factory_.GetWeakPtr(),
136                      callback),
137           base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError,
138                      weak_ptr_factory_.GetWeakPtr(),
139                      error_callback));
140 }
141
142 void BluetoothAdapterChromeOS::StopDiscovering(
143     const base::Closure& callback,
144     const ErrorCallback& error_callback) {
145   // Inform BlueZ to stop one of our open discovery sessions.
146   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
147       StopDiscovery(
148           object_path_,
149           base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery,
150                      weak_ptr_factory_.GetWeakPtr(),
151                      callback),
152           base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError,
153                      weak_ptr_factory_.GetWeakPtr(),
154                      error_callback));
155 }
156
157 void BluetoothAdapterChromeOS::ReadLocalOutOfBandPairingData(
158     const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback,
159     const ErrorCallback& error_callback) {
160   error_callback.Run();
161 }
162
163 void BluetoothAdapterChromeOS::AdapterAdded(
164     const dbus::ObjectPath& object_path) {
165   // Set the adapter to the newly added adapter only if no adapter is present.
166   if (!IsPresent())
167     SetAdapter(object_path);
168 }
169
170 void BluetoothAdapterChromeOS::AdapterRemoved(
171     const dbus::ObjectPath& object_path) {
172   if (object_path == object_path_)
173     RemoveAdapter();
174 }
175
176 void BluetoothAdapterChromeOS::AdapterPropertyChanged(
177     const dbus::ObjectPath& object_path,
178     const std::string& property_name) {
179   if (object_path != object_path_)
180     return;
181
182   BluetoothAdapterClient::Properties* properties =
183       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
184           GetProperties(object_path_);
185
186   if (property_name == properties->powered.name())
187     PoweredChanged(properties->powered.value());
188   else if (property_name == properties->discovering.name())
189     DiscoveringChanged(properties->discovering.value());
190 }
191
192 void BluetoothAdapterChromeOS::DeviceAdded(
193   const dbus::ObjectPath& object_path) {
194   BluetoothDeviceClient::Properties* properties =
195       DBusThreadManager::Get()->GetBluetoothDeviceClient()->
196           GetProperties(object_path);
197   if (properties->adapter.value() != object_path_)
198     return;
199
200   BluetoothDeviceChromeOS* device_chromeos =
201       new BluetoothDeviceChromeOS(this, object_path);
202   DCHECK(devices_.find(device_chromeos->GetAddress()) == devices_.end());
203
204   devices_[device_chromeos->GetAddress()] = device_chromeos;
205
206   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
207                     DeviceAdded(this, device_chromeos));
208 }
209
210 void BluetoothAdapterChromeOS::DeviceRemoved(
211     const dbus::ObjectPath& object_path) {
212   for (DevicesMap::iterator iter = devices_.begin();
213        iter != devices_.end(); ++iter) {
214     BluetoothDeviceChromeOS* device_chromeos =
215         static_cast<BluetoothDeviceChromeOS*>(iter->second);
216     if (device_chromeos->object_path() == object_path) {
217       devices_.erase(iter);
218
219       FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
220                         DeviceRemoved(this, device_chromeos));
221       delete device_chromeos;
222       return;
223     }
224   }
225 }
226
227 void BluetoothAdapterChromeOS::DevicePropertyChanged(
228     const dbus::ObjectPath& object_path,
229     const std::string& property_name) {
230   BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
231   if (!device_chromeos)
232     return;
233
234   BluetoothDeviceClient::Properties* properties =
235       DBusThreadManager::Get()->GetBluetoothDeviceClient()->
236           GetProperties(object_path);
237
238   if (property_name == properties->bluetooth_class.name() ||
239       property_name == properties->address.name() ||
240       property_name == properties->alias.name() ||
241       property_name == properties->paired.name() ||
242       property_name == properties->trusted.name() ||
243       property_name == properties->connected.name() ||
244       property_name == properties->uuids.name())
245     NotifyDeviceChanged(device_chromeos);
246
247   // UMA connection counting
248   if (property_name == properties->connected.name()) {
249     int count = 0;
250
251     for (DevicesMap::iterator iter = devices_.begin();
252          iter != devices_.end(); ++iter) {
253       if (iter->second->IsPaired() && iter->second->IsConnected())
254         ++count;
255     }
256
257     UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count);
258   }
259 }
260
261 void BluetoothAdapterChromeOS::InputPropertyChanged(
262     const dbus::ObjectPath& object_path,
263     const std::string& property_name) {
264   BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
265   if (!device_chromeos)
266     return;
267
268   BluetoothInputClient::Properties* properties =
269       DBusThreadManager::Get()->GetBluetoothInputClient()->
270           GetProperties(object_path);
271
272   // Properties structure can be removed, which triggers a change in the
273   // BluetoothDevice::IsConnectable() property, as does a change in the
274   // actual reconnect_mode property.
275   if (!properties ||
276       property_name == properties->reconnect_mode.name())
277     NotifyDeviceChanged(device_chromeos);
278 }
279
280 BluetoothDeviceChromeOS*
281 BluetoothAdapterChromeOS::GetDeviceWithPath(
282     const dbus::ObjectPath& object_path) {
283   for (DevicesMap::iterator iter = devices_.begin();
284        iter != devices_.end(); ++iter) {
285     BluetoothDeviceChromeOS* device_chromeos =
286         static_cast<BluetoothDeviceChromeOS*>(iter->second);
287     if (device_chromeos->object_path() == object_path)
288       return device_chromeos;
289   }
290
291   return NULL;
292 }
293
294 void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) {
295   DCHECK(!IsPresent());
296   object_path_ = object_path;
297
298   VLOG(1) << object_path_.value() << ": using adapter.";
299
300   SetAdapterName();
301
302   BluetoothAdapterClient::Properties* properties =
303       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
304           GetProperties(object_path_);
305
306   PresentChanged(true);
307
308   if (properties->powered.value())
309     PoweredChanged(true);
310   if (properties->discovering.value())
311     DiscoveringChanged(true);
312
313   std::vector<dbus::ObjectPath> device_paths =
314       DBusThreadManager::Get()->GetBluetoothDeviceClient()->
315           GetDevicesForAdapter(object_path_);
316
317   for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin();
318        iter != device_paths.end(); ++iter) {
319     BluetoothDeviceChromeOS* device_chromeos =
320         new BluetoothDeviceChromeOS(this, *iter);
321
322     devices_[device_chromeos->GetAddress()] = device_chromeos;
323
324     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
325                       DeviceAdded(this, device_chromeos));
326   }
327 }
328
329 void BluetoothAdapterChromeOS::SetAdapterName() {
330   std::string board = base::SysInfo::GetLsbReleaseBoard();
331   std::string alias;
332   if (board.substr(0, 6) == "stumpy") {
333     alias = "Chromebox";
334   } else if (board.substr(0, 4) == "link") {
335     alias = "Chromebook Pixel";
336   } else {
337     alias = "Chromebook";
338   }
339
340   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
341       GetProperties(object_path_)->alias.Set(
342           alias,
343           base::Bind(&BluetoothAdapterChromeOS::OnSetAlias,
344                      weak_ptr_factory_.GetWeakPtr()));
345 }
346
347 void BluetoothAdapterChromeOS::OnSetAlias(bool success) {
348   LOG_IF(WARNING, !success) << object_path_.value()
349                             << ": Failed to set adapter alias";
350 }
351
352 void BluetoothAdapterChromeOS::RemoveAdapter() {
353   DCHECK(IsPresent());
354   VLOG(1) << object_path_.value() << ": adapter removed.";
355
356   BluetoothAdapterClient::Properties* properties =
357       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
358           GetProperties(object_path_);
359
360   object_path_ = dbus::ObjectPath("");
361
362   if (properties->powered.value())
363     PoweredChanged(false);
364   if (properties->discovering.value())
365     DiscoveringChanged(false);
366
367   // Copy the devices list here and clear the original so that when we
368   // send DeviceRemoved(), GetDevices() returns no devices.
369   DevicesMap devices = devices_;
370   devices_.clear();
371
372   for (DevicesMap::iterator iter = devices.begin();
373        iter != devices.end(); ++iter) {
374     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
375                       DeviceRemoved(this, iter->second));
376     delete iter->second;
377   }
378
379   PresentChanged(false);
380 }
381
382 void BluetoothAdapterChromeOS::PoweredChanged(bool powered) {
383   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
384                     AdapterPoweredChanged(this, powered));
385 }
386
387 void BluetoothAdapterChromeOS::DiscoveringChanged(
388     bool discovering) {
389   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
390                     AdapterDiscoveringChanged(this, discovering));
391 }
392
393 void BluetoothAdapterChromeOS::PresentChanged(bool present) {
394   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
395                     AdapterPresentChanged(this, present));
396 }
397
398 void BluetoothAdapterChromeOS::NotifyDeviceChanged(
399     BluetoothDeviceChromeOS* device) {
400   DCHECK(device->adapter_ == this);
401
402   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
403                     DeviceChanged(this, device));
404 }
405
406 void BluetoothAdapterChromeOS::OnSetPowered(const base::Closure& callback,
407                                             const ErrorCallback& error_callback,
408                                             bool success) {
409   if (success)
410     callback.Run();
411   else
412     error_callback.Run();
413 }
414
415 void BluetoothAdapterChromeOS::OnStartDiscovery(const base::Closure& callback) {
416   callback.Run();
417 }
418
419 void BluetoothAdapterChromeOS::OnStartDiscoveryError(
420     const ErrorCallback& error_callback,
421     const std::string& error_name,
422     const std::string& error_message) {
423   LOG(WARNING) << object_path_.value() << ": Failed to start discovery: "
424                << error_name << ": " << error_message;
425   error_callback.Run();
426 }
427
428 void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure& callback) {
429   callback.Run();
430 }
431
432 void BluetoothAdapterChromeOS::OnStopDiscoveryError(
433     const ErrorCallback& error_callback,
434     const std::string& error_name,
435     const std::string& error_message) {
436   LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: "
437                << error_name << ": " << error_message;
438   error_callback.Run();
439 }
440
441 }  // namespace chromeos