Upstream version 5.34.104.0
[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 void BluetoothAdapterChromeOS::SetName(const std::string& name,
83                                        const base::Closure& callback,
84                                        const ErrorCallback& error_callback) {
85   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
86       GetProperties(object_path_)->alias.Set(
87           name,
88           base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
89                      weak_ptr_factory_.GetWeakPtr(),
90                      callback,
91                      error_callback));
92 }
93
94 bool BluetoothAdapterChromeOS::IsInitialized() const {
95   return true;
96 }
97
98 bool BluetoothAdapterChromeOS::IsPresent() const {
99   return !object_path_.value().empty();
100 }
101
102 bool BluetoothAdapterChromeOS::IsPowered() const {
103   if (!IsPresent())
104     return false;
105
106   BluetoothAdapterClient::Properties* properties =
107       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
108           GetProperties(object_path_);
109
110   return properties->powered.value();
111 }
112
113 void BluetoothAdapterChromeOS::SetPowered(
114     bool powered,
115     const base::Closure& callback,
116     const ErrorCallback& error_callback) {
117   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
118       GetProperties(object_path_)->powered.Set(
119           powered,
120           base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
121                      weak_ptr_factory_.GetWeakPtr(),
122                      callback,
123                      error_callback));
124 }
125
126 bool BluetoothAdapterChromeOS::IsDiscoverable() const {
127   if (!IsPresent())
128     return false;
129
130   BluetoothAdapterClient::Properties* properties =
131       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
132           GetProperties(object_path_);
133
134   return properties->discoverable.value();
135 }
136
137 void BluetoothAdapterChromeOS::SetDiscoverable(
138     bool discoverable,
139     const base::Closure& callback,
140     const ErrorCallback& error_callback) {
141   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
142       GetProperties(object_path_)->discoverable.Set(
143           discoverable,
144           base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoverable,
145                      weak_ptr_factory_.GetWeakPtr(),
146                      callback,
147                      error_callback));
148 }
149
150 bool BluetoothAdapterChromeOS::IsDiscovering() const {
151   if (!IsPresent())
152     return false;
153
154   BluetoothAdapterClient::Properties* properties =
155       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
156           GetProperties(object_path_);
157
158   return properties->discovering.value();
159 }
160
161 void BluetoothAdapterChromeOS::StartDiscovering(
162     const base::Closure& callback,
163     const ErrorCallback& error_callback) {
164   // BlueZ counts discovery sessions, and permits multiple sessions for a
165   // single connection, so issue a StartDiscovery() call for every use
166   // within Chromium for the right behavior.
167   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
168       StartDiscovery(
169           object_path_,
170           base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery,
171                      weak_ptr_factory_.GetWeakPtr(),
172                      callback),
173           base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError,
174                      weak_ptr_factory_.GetWeakPtr(),
175                      error_callback));
176 }
177
178 void BluetoothAdapterChromeOS::StopDiscovering(
179     const base::Closure& callback,
180     const ErrorCallback& error_callback) {
181   // Inform BlueZ to stop one of our open discovery sessions.
182   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
183       StopDiscovery(
184           object_path_,
185           base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery,
186                      weak_ptr_factory_.GetWeakPtr(),
187                      callback),
188           base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError,
189                      weak_ptr_factory_.GetWeakPtr(),
190                      error_callback));
191 }
192
193 void BluetoothAdapterChromeOS::ReadLocalOutOfBandPairingData(
194     const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback,
195     const ErrorCallback& error_callback) {
196   error_callback.Run();
197 }
198
199 void BluetoothAdapterChromeOS::AdapterAdded(
200     const dbus::ObjectPath& object_path) {
201   // Set the adapter to the newly added adapter only if no adapter is present.
202   if (!IsPresent())
203     SetAdapter(object_path);
204 }
205
206 void BluetoothAdapterChromeOS::AdapterRemoved(
207     const dbus::ObjectPath& object_path) {
208   if (object_path == object_path_)
209     RemoveAdapter();
210 }
211
212 void BluetoothAdapterChromeOS::AdapterPropertyChanged(
213     const dbus::ObjectPath& object_path,
214     const std::string& property_name) {
215   if (object_path != object_path_)
216     return;
217
218   BluetoothAdapterClient::Properties* properties =
219       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
220           GetProperties(object_path_);
221
222   if (property_name == properties->powered.name())
223     PoweredChanged(properties->powered.value());
224   else if (property_name == properties->discoverable.name())
225     DiscoverableChanged(properties->discoverable.value());
226   else if (property_name == properties->discovering.name())
227     DiscoveringChanged(properties->discovering.value());
228 }
229
230 void BluetoothAdapterChromeOS::DeviceAdded(
231   const dbus::ObjectPath& object_path) {
232   BluetoothDeviceClient::Properties* properties =
233       DBusThreadManager::Get()->GetBluetoothDeviceClient()->
234           GetProperties(object_path);
235   if (properties->adapter.value() != object_path_)
236     return;
237
238   BluetoothDeviceChromeOS* device_chromeos =
239       new BluetoothDeviceChromeOS(this, object_path);
240   DCHECK(devices_.find(device_chromeos->GetAddress()) == devices_.end());
241
242   devices_[device_chromeos->GetAddress()] = device_chromeos;
243
244   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
245                     DeviceAdded(this, device_chromeos));
246 }
247
248 void BluetoothAdapterChromeOS::DeviceRemoved(
249     const dbus::ObjectPath& object_path) {
250   for (DevicesMap::iterator iter = devices_.begin();
251        iter != devices_.end(); ++iter) {
252     BluetoothDeviceChromeOS* device_chromeos =
253         static_cast<BluetoothDeviceChromeOS*>(iter->second);
254     if (device_chromeos->object_path() == object_path) {
255       devices_.erase(iter);
256
257       FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
258                         DeviceRemoved(this, device_chromeos));
259       delete device_chromeos;
260       return;
261     }
262   }
263 }
264
265 void BluetoothAdapterChromeOS::DevicePropertyChanged(
266     const dbus::ObjectPath& object_path,
267     const std::string& property_name) {
268   BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
269   if (!device_chromeos)
270     return;
271
272   BluetoothDeviceClient::Properties* properties =
273       DBusThreadManager::Get()->GetBluetoothDeviceClient()->
274           GetProperties(object_path);
275
276   if (property_name == properties->bluetooth_class.name() ||
277       property_name == properties->address.name() ||
278       property_name == properties->alias.name() ||
279       property_name == properties->paired.name() ||
280       property_name == properties->trusted.name() ||
281       property_name == properties->connected.name() ||
282       property_name == properties->uuids.name())
283     NotifyDeviceChanged(device_chromeos);
284
285   // UMA connection counting
286   if (property_name == properties->connected.name()) {
287     int count = 0;
288
289     for (DevicesMap::iterator iter = devices_.begin();
290          iter != devices_.end(); ++iter) {
291       if (iter->second->IsPaired() && iter->second->IsConnected())
292         ++count;
293     }
294
295     UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count);
296   }
297 }
298
299 void BluetoothAdapterChromeOS::InputPropertyChanged(
300     const dbus::ObjectPath& object_path,
301     const std::string& property_name) {
302   BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
303   if (!device_chromeos)
304     return;
305
306   BluetoothInputClient::Properties* properties =
307       DBusThreadManager::Get()->GetBluetoothInputClient()->
308           GetProperties(object_path);
309
310   // Properties structure can be removed, which triggers a change in the
311   // BluetoothDevice::IsConnectable() property, as does a change in the
312   // actual reconnect_mode property.
313   if (!properties ||
314       property_name == properties->reconnect_mode.name())
315     NotifyDeviceChanged(device_chromeos);
316 }
317
318 BluetoothDeviceChromeOS*
319 BluetoothAdapterChromeOS::GetDeviceWithPath(
320     const dbus::ObjectPath& object_path) {
321   for (DevicesMap::iterator iter = devices_.begin();
322        iter != devices_.end(); ++iter) {
323     BluetoothDeviceChromeOS* device_chromeos =
324         static_cast<BluetoothDeviceChromeOS*>(iter->second);
325     if (device_chromeos->object_path() == object_path)
326       return device_chromeos;
327   }
328
329   return NULL;
330 }
331
332 void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) {
333   DCHECK(!IsPresent());
334   object_path_ = object_path;
335
336   VLOG(1) << object_path_.value() << ": using adapter.";
337
338   SetDefaultAdapterName();
339
340   BluetoothAdapterClient::Properties* properties =
341       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
342           GetProperties(object_path_);
343
344   PresentChanged(true);
345
346   if (properties->powered.value())
347     PoweredChanged(true);
348   if (properties->discoverable.value())
349     DiscoverableChanged(true);
350   if (properties->discovering.value())
351     DiscoveringChanged(true);
352
353   std::vector<dbus::ObjectPath> device_paths =
354       DBusThreadManager::Get()->GetBluetoothDeviceClient()->
355           GetDevicesForAdapter(object_path_);
356
357   for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin();
358        iter != device_paths.end(); ++iter) {
359     BluetoothDeviceChromeOS* device_chromeos =
360         new BluetoothDeviceChromeOS(this, *iter);
361
362     devices_[device_chromeos->GetAddress()] = device_chromeos;
363
364     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
365                       DeviceAdded(this, device_chromeos));
366   }
367 }
368
369 void BluetoothAdapterChromeOS::SetDefaultAdapterName() {
370   std::string board = base::SysInfo::GetLsbReleaseBoard();
371   std::string alias;
372   if (board.substr(0, 6) == "stumpy") {
373     alias = "Chromebox";
374   } else if (board.substr(0, 4) == "link") {
375     alias = "Chromebook Pixel";
376   } else {
377     alias = "Chromebook";
378   }
379
380   SetName(alias, base::Bind(&base::DoNothing), base::Bind(&base::DoNothing));
381 }
382
383 void BluetoothAdapterChromeOS::RemoveAdapter() {
384   DCHECK(IsPresent());
385   VLOG(1) << object_path_.value() << ": adapter removed.";
386
387   BluetoothAdapterClient::Properties* properties =
388       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
389           GetProperties(object_path_);
390
391   object_path_ = dbus::ObjectPath("");
392
393   if (properties->powered.value())
394     PoweredChanged(false);
395   if (properties->discoverable.value())
396     DiscoverableChanged(false);
397   if (properties->discovering.value())
398     DiscoveringChanged(false);
399
400   // Copy the devices list here and clear the original so that when we
401   // send DeviceRemoved(), GetDevices() returns no devices.
402   DevicesMap devices = devices_;
403   devices_.clear();
404
405   for (DevicesMap::iterator iter = devices.begin();
406        iter != devices.end(); ++iter) {
407     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
408                       DeviceRemoved(this, iter->second));
409     delete iter->second;
410   }
411
412   PresentChanged(false);
413 }
414
415 void BluetoothAdapterChromeOS::PoweredChanged(bool powered) {
416   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
417                     AdapterPoweredChanged(this, powered));
418 }
419
420 void BluetoothAdapterChromeOS::DiscoverableChanged(bool discoverable) {
421   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
422                     AdapterDiscoverableChanged(this, discoverable));
423 }
424
425 void BluetoothAdapterChromeOS::DiscoveringChanged(
426     bool discovering) {
427   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
428                     AdapterDiscoveringChanged(this, discovering));
429 }
430
431 void BluetoothAdapterChromeOS::PresentChanged(bool present) {
432   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
433                     AdapterPresentChanged(this, present));
434 }
435
436 void BluetoothAdapterChromeOS::NotifyDeviceChanged(
437     BluetoothDeviceChromeOS* device) {
438   DCHECK(device->adapter_ == this);
439
440   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
441                     DeviceChanged(this, device));
442 }
443
444 void BluetoothAdapterChromeOS::OnSetDiscoverable(
445     const base::Closure& callback,
446     const ErrorCallback& error_callback,
447     bool success) {
448   // Set the discoverable_timeout property to zero so the adapter remains
449   // discoverable forever.
450   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
451       GetProperties(object_path_)->discoverable_timeout.Set(
452           0,
453           base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
454                      weak_ptr_factory_.GetWeakPtr(),
455                      callback,
456                      error_callback));
457 }
458
459 void BluetoothAdapterChromeOS::OnPropertyChangeCompleted(
460     const base::Closure& callback,
461     const ErrorCallback& error_callback,
462     bool success) {
463   if (success)
464     callback.Run();
465   else
466     error_callback.Run();
467 }
468
469 void BluetoothAdapterChromeOS::OnStartDiscovery(const base::Closure& callback) {
470   callback.Run();
471 }
472
473 void BluetoothAdapterChromeOS::OnStartDiscoveryError(
474     const ErrorCallback& error_callback,
475     const std::string& error_name,
476     const std::string& error_message) {
477   LOG(WARNING) << object_path_.value() << ": Failed to start discovery: "
478                << error_name << ": " << error_message;
479   error_callback.Run();
480 }
481
482 void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure& callback) {
483   callback.Run();
484 }
485
486 void BluetoothAdapterChromeOS::OnStopDiscoveryError(
487     const ErrorCallback& error_callback,
488     const std::string& error_name,
489     const std::string& error_message) {
490   LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: "
491                << error_name << ": " << error_message;
492   error_callback.Run();
493 }
494
495 }  // namespace chromeos