Upstream version 11.40.277.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/sequenced_task_runner.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/sys_info.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "chromeos/dbus/bluetooth_adapter_client.h"
17 #include "chromeos/dbus/bluetooth_agent_manager_client.h"
18 #include "chromeos/dbus/bluetooth_agent_service_provider.h"
19 #include "chromeos/dbus/bluetooth_device_client.h"
20 #include "chromeos/dbus/bluetooth_input_client.h"
21 #include "chromeos/dbus/dbus_thread_manager.h"
22 #include "device/bluetooth/bluetooth_device.h"
23 #include "device/bluetooth/bluetooth_device_chromeos.h"
24 #include "device/bluetooth/bluetooth_pairing_chromeos.h"
25 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h"
26 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h"
27 #include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h"
28 #include "device/bluetooth/bluetooth_socket_chromeos.h"
29 #include "device/bluetooth/bluetooth_socket_thread.h"
30 #include "device/bluetooth/bluetooth_uuid.h"
31 #include "third_party/cros_system_api/dbus/service_constants.h"
32
33 using device::BluetoothAdapter;
34 using device::BluetoothDevice;
35 using device::BluetoothSocket;
36 using device::BluetoothUUID;
37
38 namespace {
39
40 // The agent path is relatively meaningless since BlueZ only permits one to
41 // exist per D-Bus connection, it just has to be unique within Chromium.
42 const char kAgentPath[] = "/org/chromium/bluetooth_agent";
43
44 void OnUnregisterAgentError(const std::string& error_name,
45                             const std::string& error_message) {
46   // It's okay if the agent didn't exist, it means we never saw an adapter.
47   if (error_name == bluetooth_agent_manager::kErrorDoesNotExist)
48     return;
49
50   LOG(WARNING) << "Failed to unregister pairing agent: "
51                << error_name << ": " << error_message;
52 }
53
54 }  // namespace
55
56 namespace device {
57
58 // static
59 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
60     const InitCallback& init_callback) {
61   return chromeos::BluetoothAdapterChromeOS::CreateAdapter();
62 }
63
64 }
65
66 namespace chromeos {
67
68 // static
69 base::WeakPtr<BluetoothAdapter> BluetoothAdapterChromeOS::CreateAdapter() {
70   BluetoothAdapterChromeOS* adapter = new BluetoothAdapterChromeOS();
71   return adapter->weak_ptr_factory_.GetWeakPtr();
72 }
73
74 BluetoothAdapterChromeOS::BluetoothAdapterChromeOS()
75     : num_discovery_sessions_(0),
76       discovery_request_pending_(false),
77       weak_ptr_factory_(this) {
78   ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
79   socket_thread_ = device::BluetoothSocketThread::Get();
80
81   DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this);
82   DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this);
83   DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this);
84
85   // Register the pairing agent.
86   dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
87   agent_.reset(BluetoothAgentServiceProvider::Create(
88       system_bus, dbus::ObjectPath(kAgentPath), this));
89   DCHECK(agent_.get());
90
91   std::vector<dbus::ObjectPath> object_paths =
92       DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters();
93
94   if (!object_paths.empty()) {
95     VLOG(1) << object_paths.size() << " Bluetooth adapter(s) available.";
96     SetAdapter(object_paths[0]);
97   }
98 }
99
100 BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() {
101   DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this);
102   DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this);
103   DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this);
104
105   VLOG(1) << "Unregistering pairing agent";
106   DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
107       UnregisterAgent(
108           dbus::ObjectPath(kAgentPath),
109           base::Bind(&base::DoNothing),
110           base::Bind(&OnUnregisterAgentError));
111 }
112
113 void BluetoothAdapterChromeOS::AddObserver(
114     BluetoothAdapter::Observer* observer) {
115   DCHECK(observer);
116   observers_.AddObserver(observer);
117 }
118
119 void BluetoothAdapterChromeOS::RemoveObserver(
120     BluetoothAdapter::Observer* observer) {
121   DCHECK(observer);
122   observers_.RemoveObserver(observer);
123 }
124
125 std::string BluetoothAdapterChromeOS::GetAddress() const {
126   if (!IsPresent())
127     return std::string();
128
129   BluetoothAdapterClient::Properties* properties =
130       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
131           GetProperties(object_path_);
132   DCHECK(properties);
133
134   return BluetoothDevice::CanonicalizeAddress(properties->address.value());
135 }
136
137 std::string BluetoothAdapterChromeOS::GetName() const {
138   if (!IsPresent())
139     return std::string();
140
141   BluetoothAdapterClient::Properties* properties =
142       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
143           GetProperties(object_path_);
144   DCHECK(properties);
145
146   return properties->alias.value();
147 }
148
149 void BluetoothAdapterChromeOS::SetName(const std::string& name,
150                                        const base::Closure& callback,
151                                        const ErrorCallback& error_callback) {
152   if (!IsPresent())
153     error_callback.Run();
154
155   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
156       GetProperties(object_path_)->alias.Set(
157           name,
158           base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
159                      weak_ptr_factory_.GetWeakPtr(),
160                      callback,
161                      error_callback));
162 }
163
164 bool BluetoothAdapterChromeOS::IsInitialized() const {
165   return true;
166 }
167
168 bool BluetoothAdapterChromeOS::IsPresent() const {
169   return !object_path_.value().empty();
170 }
171
172 bool BluetoothAdapterChromeOS::IsPowered() const {
173   if (!IsPresent())
174     return false;
175
176   BluetoothAdapterClient::Properties* properties =
177       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
178           GetProperties(object_path_);
179
180   return properties->powered.value();
181 }
182
183 void BluetoothAdapterChromeOS::SetPowered(
184     bool powered,
185     const base::Closure& callback,
186     const ErrorCallback& error_callback) {
187   if (!IsPresent())
188     error_callback.Run();
189
190   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
191       GetProperties(object_path_)->powered.Set(
192           powered,
193           base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
194                      weak_ptr_factory_.GetWeakPtr(),
195                      callback,
196                      error_callback));
197 }
198
199 bool BluetoothAdapterChromeOS::IsDiscoverable() const {
200   if (!IsPresent())
201     return false;
202
203   BluetoothAdapterClient::Properties* properties =
204       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
205           GetProperties(object_path_);
206
207   return properties->discoverable.value();
208 }
209
210 void BluetoothAdapterChromeOS::SetDiscoverable(
211     bool discoverable,
212     const base::Closure& callback,
213     const ErrorCallback& error_callback) {
214   if (!IsPresent())
215     error_callback.Run();
216
217   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
218       GetProperties(object_path_)->discoverable.Set(
219           discoverable,
220           base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoverable,
221                      weak_ptr_factory_.GetWeakPtr(),
222                      callback,
223                      error_callback));
224 }
225
226 bool BluetoothAdapterChromeOS::IsDiscovering() const {
227   if (!IsPresent())
228     return false;
229
230   BluetoothAdapterClient::Properties* properties =
231       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
232           GetProperties(object_path_);
233
234   return properties->discovering.value();
235 }
236
237 void BluetoothAdapterChromeOS::CreateRfcommService(
238     const BluetoothUUID& uuid,
239     const ServiceOptions& options,
240     const CreateServiceCallback& callback,
241     const CreateServiceErrorCallback& error_callback) {
242   VLOG(1) << object_path_.value() << ": Creating RFCOMM service: "
243           << uuid.canonical_value();
244   scoped_refptr<BluetoothSocketChromeOS> socket =
245       BluetoothSocketChromeOS::CreateBluetoothSocket(
246           ui_task_runner_, socket_thread_);
247   socket->Listen(this,
248                  BluetoothSocketChromeOS::kRfcomm,
249                  uuid,
250                  options,
251                  base::Bind(callback, socket),
252                  error_callback);
253 }
254
255 void BluetoothAdapterChromeOS::CreateL2capService(
256     const BluetoothUUID& uuid,
257     const ServiceOptions& options,
258     const CreateServiceCallback& callback,
259     const CreateServiceErrorCallback& error_callback) {
260   VLOG(1) << object_path_.value() << ": Creating L2CAP service: "
261           << uuid.canonical_value();
262   scoped_refptr<BluetoothSocketChromeOS> socket =
263       BluetoothSocketChromeOS::CreateBluetoothSocket(
264           ui_task_runner_, socket_thread_);
265   socket->Listen(this,
266                  BluetoothSocketChromeOS::kL2cap,
267                  uuid,
268                  options,
269                  base::Bind(callback, socket),
270                  error_callback);
271 }
272
273 void BluetoothAdapterChromeOS::RemovePairingDelegateInternal(
274     BluetoothDevice::PairingDelegate* pairing_delegate) {
275   // Before removing a pairing delegate make sure that there aren't any devices
276   // currently using it; if there are, clear the pairing context which will
277   // make any responses no-ops.
278   for (DevicesMap::iterator iter = devices_.begin();
279        iter != devices_.end(); ++iter) {
280     BluetoothDeviceChromeOS* device_chromeos =
281         static_cast<BluetoothDeviceChromeOS*>(iter->second);
282
283     BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
284     if (pairing && pairing->GetPairingDelegate() == pairing_delegate)
285       device_chromeos->EndPairing();
286   }
287 }
288
289 void BluetoothAdapterChromeOS::AdapterAdded(
290     const dbus::ObjectPath& object_path) {
291   // Set the adapter to the newly added adapter only if no adapter is present.
292   if (!IsPresent())
293     SetAdapter(object_path);
294 }
295
296 void BluetoothAdapterChromeOS::AdapterRemoved(
297     const dbus::ObjectPath& object_path) {
298   if (object_path == object_path_)
299     RemoveAdapter();
300 }
301
302 void BluetoothAdapterChromeOS::AdapterPropertyChanged(
303     const dbus::ObjectPath& object_path,
304     const std::string& property_name) {
305   if (object_path != object_path_)
306     return;
307
308   BluetoothAdapterClient::Properties* properties =
309       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
310           GetProperties(object_path_);
311
312   if (property_name == properties->powered.name())
313     PoweredChanged(properties->powered.value());
314   else if (property_name == properties->discoverable.name())
315     DiscoverableChanged(properties->discoverable.value());
316   else if (property_name == properties->discovering.name())
317     DiscoveringChanged(properties->discovering.value());
318 }
319
320 void BluetoothAdapterChromeOS::DeviceAdded(
321   const dbus::ObjectPath& object_path) {
322   BluetoothDeviceClient::Properties* properties =
323       DBusThreadManager::Get()->GetBluetoothDeviceClient()->
324           GetProperties(object_path);
325   if (properties->adapter.value() != object_path_)
326     return;
327
328   BluetoothDeviceChromeOS* device_chromeos =
329       new BluetoothDeviceChromeOS(this,
330                                   object_path,
331                                   ui_task_runner_,
332                                   socket_thread_);
333   DCHECK(devices_.find(device_chromeos->GetAddress()) == devices_.end());
334
335   devices_[device_chromeos->GetAddress()] = device_chromeos;
336
337   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
338                     DeviceAdded(this, device_chromeos));
339 }
340
341 void BluetoothAdapterChromeOS::DeviceRemoved(
342     const dbus::ObjectPath& object_path) {
343   for (DevicesMap::iterator iter = devices_.begin();
344        iter != devices_.end(); ++iter) {
345     BluetoothDeviceChromeOS* device_chromeos =
346         static_cast<BluetoothDeviceChromeOS*>(iter->second);
347     if (device_chromeos->object_path() == object_path) {
348       devices_.erase(iter);
349
350       FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
351                         DeviceRemoved(this, device_chromeos));
352       delete device_chromeos;
353       return;
354     }
355   }
356 }
357
358 void BluetoothAdapterChromeOS::DevicePropertyChanged(
359     const dbus::ObjectPath& object_path,
360     const std::string& property_name) {
361   BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
362   if (!device_chromeos)
363     return;
364
365   BluetoothDeviceClient::Properties* properties =
366       DBusThreadManager::Get()->GetBluetoothDeviceClient()->
367           GetProperties(object_path);
368
369   if (property_name == properties->bluetooth_class.name() ||
370       property_name == properties->address.name() ||
371       property_name == properties->alias.name() ||
372       property_name == properties->paired.name() ||
373       property_name == properties->trusted.name() ||
374       property_name == properties->connected.name() ||
375       property_name == properties->uuids.name() ||
376       property_name == properties->rssi.name() ||
377       property_name == properties->connection_rssi.name() ||
378       property_name == properties->connection_tx_power.name())
379     NotifyDeviceChanged(device_chromeos);
380
381   // When a device becomes paired, mark it as trusted so that the user does
382   // not need to approve every incoming connection
383   if (property_name == properties->paired.name() &&
384       properties->paired.value() && !properties->trusted.value())
385     device_chromeos->SetTrusted();
386
387   // UMA connection counting
388   if (property_name == properties->connected.name()) {
389     // PlayStation joystick tries to reconnect after disconnection from USB.
390     // If it is still not trusted, set it, so it becomes available on the
391     // list of known devices.
392     if (properties->connected.value() && device_chromeos->IsTrustable() &&
393         !properties->trusted.value())
394       device_chromeos->SetTrusted();
395
396     int count = 0;
397
398     for (DevicesMap::iterator iter = devices_.begin();
399          iter != devices_.end(); ++iter) {
400       if (iter->second->IsPaired() && iter->second->IsConnected())
401         ++count;
402     }
403
404     UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count);
405   }
406 }
407
408 void BluetoothAdapterChromeOS::InputPropertyChanged(
409     const dbus::ObjectPath& object_path,
410     const std::string& property_name) {
411   BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
412   if (!device_chromeos)
413     return;
414
415   BluetoothInputClient::Properties* properties =
416       DBusThreadManager::Get()->GetBluetoothInputClient()->
417           GetProperties(object_path);
418
419   // Properties structure can be removed, which triggers a change in the
420   // BluetoothDevice::IsConnectable() property, as does a change in the
421   // actual reconnect_mode property.
422   if (!properties ||
423       property_name == properties->reconnect_mode.name())
424     NotifyDeviceChanged(device_chromeos);
425 }
426
427 void BluetoothAdapterChromeOS::Released() {
428   DCHECK(agent_.get());
429   VLOG(1) << "Release";
430
431   // Called after we unregister the pairing agent, e.g. when changing I/O
432   // capabilities. Nothing much to be done right now.
433 }
434
435 void BluetoothAdapterChromeOS::RequestPinCode(
436     const dbus::ObjectPath& device_path,
437     const PinCodeCallback& callback) {
438   DCHECK(agent_.get());
439   VLOG(1) << device_path.value() << ": RequestPinCode";
440
441   BluetoothPairingChromeOS* pairing = GetPairing(device_path);
442   if (!pairing) {
443     callback.Run(REJECTED, "");
444     return;
445   }
446
447   pairing->RequestPinCode(callback);
448 }
449
450 void BluetoothAdapterChromeOS::DisplayPinCode(
451     const dbus::ObjectPath& device_path,
452     const std::string& pincode) {
453   DCHECK(agent_.get());
454   VLOG(1) << device_path.value() << ": DisplayPinCode: " << pincode;
455
456   BluetoothPairingChromeOS* pairing = GetPairing(device_path);
457   if (!pairing)
458     return;
459
460   pairing->DisplayPinCode(pincode);
461 }
462
463 void BluetoothAdapterChromeOS::RequestPasskey(
464     const dbus::ObjectPath& device_path,
465     const PasskeyCallback& callback) {
466   DCHECK(agent_.get());
467   VLOG(1) << device_path.value() << ": RequestPasskey";
468
469   BluetoothPairingChromeOS* pairing = GetPairing(device_path);
470   if (!pairing) {
471     callback.Run(REJECTED, 0);
472     return;
473   }
474
475   pairing->RequestPasskey(callback);
476 }
477
478 void BluetoothAdapterChromeOS::DisplayPasskey(
479     const dbus::ObjectPath& device_path,
480     uint32 passkey,
481     uint16 entered) {
482   DCHECK(agent_.get());
483   VLOG(1) << device_path.value() << ": DisplayPasskey: " << passkey
484           << " (" << entered << " entered)";
485
486   BluetoothPairingChromeOS* pairing = GetPairing(device_path);
487   if (!pairing)
488     return;
489
490   if (entered == 0)
491     pairing->DisplayPasskey(passkey);
492
493   pairing->KeysEntered(entered);
494 }
495
496 void BluetoothAdapterChromeOS::RequestConfirmation(
497     const dbus::ObjectPath& device_path,
498     uint32 passkey,
499     const ConfirmationCallback& callback) {
500   DCHECK(agent_.get());
501   VLOG(1) << device_path.value() << ": RequestConfirmation: " << passkey;
502
503   BluetoothPairingChromeOS* pairing = GetPairing(device_path);
504   if (!pairing) {
505     callback.Run(REJECTED);
506     return;
507   }
508
509   pairing->RequestConfirmation(passkey, callback);
510 }
511
512 void BluetoothAdapterChromeOS::RequestAuthorization(
513     const dbus::ObjectPath& device_path,
514     const ConfirmationCallback& callback) {
515   DCHECK(agent_.get());
516   VLOG(1) << device_path.value() << ": RequestAuthorization";
517
518   BluetoothPairingChromeOS* pairing = GetPairing(device_path);
519   if (!pairing) {
520     callback.Run(REJECTED);
521     return;
522   }
523
524   pairing->RequestAuthorization(callback);
525 }
526
527 void BluetoothAdapterChromeOS::AuthorizeService(
528     const dbus::ObjectPath& device_path,
529     const std::string& uuid,
530     const ConfirmationCallback& callback) {
531   DCHECK(agent_.get());
532   VLOG(1) << device_path.value() << ": AuthorizeService: " << uuid;
533
534   BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(device_path);
535   if (!device_chromeos) {
536     callback.Run(CANCELLED);
537     return;
538   }
539
540   // We always set paired devices to Trusted, so the only reason that this
541   // method call would ever be called is in the case of a race condition where
542   // our "Set('Trusted', true)" method call is still pending in the Bluetooth
543   // daemon because it's busy handling the incoming connection.
544   if (device_chromeos->IsPaired()) {
545     callback.Run(SUCCESS);
546     return;
547   }
548
549   // TODO(keybuk): reject service authorizations when not paired, determine
550   // whether this is acceptable long-term.
551   LOG(WARNING) << "Rejecting service connection from unpaired device "
552                << device_chromeos->GetAddress() << " for UUID " << uuid;
553   callback.Run(REJECTED);
554 }
555
556 void BluetoothAdapterChromeOS::Cancel() {
557   DCHECK(agent_.get());
558   VLOG(1) << "Cancel";
559 }
560
561 void BluetoothAdapterChromeOS::OnRegisterAgent() {
562   VLOG(1) << "Pairing agent registered, requesting to be made default";
563
564   DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
565       RequestDefaultAgent(
566           dbus::ObjectPath(kAgentPath),
567           base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgent,
568                      weak_ptr_factory_.GetWeakPtr()),
569           base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgentError,
570                      weak_ptr_factory_.GetWeakPtr()));
571
572 }
573
574 void BluetoothAdapterChromeOS::OnRegisterAgentError(
575     const std::string& error_name,
576     const std::string& error_message) {
577   // Our agent being already registered isn't an error.
578   if (error_name == bluetooth_agent_manager::kErrorAlreadyExists)
579     return;
580
581   LOG(WARNING) << ": Failed to register pairing agent: "
582                << error_name << ": " << error_message;
583 }
584
585 void BluetoothAdapterChromeOS::OnRequestDefaultAgent() {
586   VLOG(1) << "Pairing agent now default";
587 }
588
589 void BluetoothAdapterChromeOS::OnRequestDefaultAgentError(
590     const std::string& error_name,
591     const std::string& error_message) {
592   LOG(WARNING) << ": Failed to make pairing agent default: "
593                << error_name << ": " << error_message;
594 }
595
596 BluetoothDeviceChromeOS*
597 BluetoothAdapterChromeOS::GetDeviceWithPath(
598     const dbus::ObjectPath& object_path) {
599   for (DevicesMap::iterator iter = devices_.begin();
600        iter != devices_.end(); ++iter) {
601     BluetoothDeviceChromeOS* device_chromeos =
602         static_cast<BluetoothDeviceChromeOS*>(iter->second);
603     if (device_chromeos->object_path() == object_path)
604       return device_chromeos;
605   }
606
607   return NULL;
608 }
609
610 BluetoothPairingChromeOS* BluetoothAdapterChromeOS::GetPairing(
611     const dbus::ObjectPath& object_path)
612 {
613   BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
614   if (!device_chromeos) {
615     LOG(WARNING) << "Pairing Agent request for unknown device: "
616                  << object_path.value();
617     return NULL;
618   }
619
620   BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
621   if (pairing)
622     return pairing;
623
624   // The device doesn't have its own pairing context, so this is an incoming
625   // pairing request that should use our best default delegate (if we have one).
626   BluetoothDevice::PairingDelegate* pairing_delegate = DefaultPairingDelegate();
627   if (!pairing_delegate)
628     return NULL;
629
630   return device_chromeos->BeginPairing(pairing_delegate);
631 }
632
633 void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) {
634   DCHECK(!IsPresent());
635   object_path_ = object_path;
636
637   VLOG(1) << object_path_.value() << ": using adapter.";
638
639   VLOG(1) << "Registering pairing agent";
640   DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
641       RegisterAgent(
642           dbus::ObjectPath(kAgentPath),
643           bluetooth_agent_manager::kKeyboardDisplayCapability,
644           base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgent,
645                      weak_ptr_factory_.GetWeakPtr()),
646           base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgentError,
647                      weak_ptr_factory_.GetWeakPtr()));
648
649   SetDefaultAdapterName();
650
651   BluetoothAdapterClient::Properties* properties =
652       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
653           GetProperties(object_path_);
654
655   PresentChanged(true);
656
657   if (properties->powered.value())
658     PoweredChanged(true);
659   if (properties->discoverable.value())
660     DiscoverableChanged(true);
661   if (properties->discovering.value())
662     DiscoveringChanged(true);
663
664   std::vector<dbus::ObjectPath> device_paths =
665       DBusThreadManager::Get()->GetBluetoothDeviceClient()->
666           GetDevicesForAdapter(object_path_);
667
668   for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin();
669        iter != device_paths.end(); ++iter) {
670     DeviceAdded(*iter);
671   }
672 }
673
674 void BluetoothAdapterChromeOS::SetDefaultAdapterName() {
675   std::string board = base::SysInfo::GetLsbReleaseBoard();
676   std::string alias;
677   if (board.substr(0, 6) == "stumpy") {
678     alias = "Chromebox";
679   } else if (board.substr(0, 4) == "link") {
680     alias = "Chromebook Pixel";
681   } else {
682     alias = "Chromebook";
683   }
684
685   SetName(alias, base::Bind(&base::DoNothing), base::Bind(&base::DoNothing));
686 }
687
688 void BluetoothAdapterChromeOS::RemoveAdapter() {
689   DCHECK(IsPresent());
690   VLOG(1) << object_path_.value() << ": adapter removed.";
691
692   BluetoothAdapterClient::Properties* properties =
693       DBusThreadManager::Get()->GetBluetoothAdapterClient()->
694           GetProperties(object_path_);
695
696   object_path_ = dbus::ObjectPath("");
697
698   if (properties->powered.value())
699     PoweredChanged(false);
700   if (properties->discoverable.value())
701     DiscoverableChanged(false);
702   if (properties->discovering.value())
703     DiscoveringChanged(false);
704
705   // Copy the devices list here and clear the original so that when we
706   // send DeviceRemoved(), GetDevices() returns no devices.
707   DevicesMap devices = devices_;
708   devices_.clear();
709
710   for (DevicesMap::iterator iter = devices.begin();
711        iter != devices.end(); ++iter) {
712     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
713                       DeviceRemoved(this, iter->second));
714     delete iter->second;
715   }
716
717   PresentChanged(false);
718 }
719
720 void BluetoothAdapterChromeOS::PoweredChanged(bool powered) {
721   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
722                     AdapterPoweredChanged(this, powered));
723 }
724
725 void BluetoothAdapterChromeOS::DiscoverableChanged(bool discoverable) {
726   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
727                     AdapterDiscoverableChanged(this, discoverable));
728 }
729
730 void BluetoothAdapterChromeOS::DiscoveringChanged(
731     bool discovering) {
732   // If the adapter stopped discovery due to a reason other than a request by
733   // us, reset the count to 0.
734   VLOG(1) << "Discovering changed: " << discovering;
735   if (!discovering && !discovery_request_pending_
736       && num_discovery_sessions_ > 0) {
737     VLOG(1) << "Marking sessions as inactive.";
738     num_discovery_sessions_ = 0;
739     MarkDiscoverySessionsAsInactive();
740   }
741   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
742                     AdapterDiscoveringChanged(this, discovering));
743 }
744
745 void BluetoothAdapterChromeOS::PresentChanged(bool present) {
746   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
747                     AdapterPresentChanged(this, present));
748 }
749
750 void BluetoothAdapterChromeOS::NotifyDeviceChanged(
751     BluetoothDeviceChromeOS* device) {
752   DCHECK(device->adapter_ == this);
753
754   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
755                     DeviceChanged(this, device));
756 }
757
758 void BluetoothAdapterChromeOS::NotifyGattServiceAdded(
759     BluetoothRemoteGattServiceChromeOS* service) {
760   DCHECK_EQ(service->GetAdapter(), this);
761   DCHECK_EQ(
762       static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_,
763       this);
764
765   FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
766                     observers_,
767                     GattServiceAdded(this, service->GetDevice(), service));
768 }
769
770 void BluetoothAdapterChromeOS::NotifyGattServiceRemoved(
771     BluetoothRemoteGattServiceChromeOS* service) {
772   DCHECK_EQ(service->GetAdapter(), this);
773   DCHECK_EQ(
774       static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_,
775       this);
776
777   FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
778                     observers_,
779                     GattServiceRemoved(this, service->GetDevice(), service));
780 }
781
782 void BluetoothAdapterChromeOS::NotifyGattServiceChanged(
783     BluetoothRemoteGattServiceChromeOS* service) {
784   DCHECK_EQ(service->GetAdapter(), this);
785
786   FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
787                     observers_,
788                     GattServiceChanged(this, service));
789 }
790
791 void BluetoothAdapterChromeOS::NotifyGattDiscoveryComplete(
792     BluetoothRemoteGattServiceChromeOS* service) {
793   DCHECK_EQ(service->GetAdapter(), this);
794
795   FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
796                     observers_,
797                     GattDiscoveryCompleteForService(this, service));
798 }
799
800 void BluetoothAdapterChromeOS::NotifyGattCharacteristicAdded(
801     BluetoothRemoteGattCharacteristicChromeOS* characteristic) {
802   DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
803                 characteristic->GetService())->GetAdapter(),
804             this);
805
806   FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
807                     observers_,
808                     GattCharacteristicAdded(this, characteristic));
809 }
810
811 void BluetoothAdapterChromeOS::NotifyGattCharacteristicRemoved(
812     BluetoothRemoteGattCharacteristicChromeOS* characteristic) {
813   DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
814                 characteristic->GetService())->GetAdapter(),
815             this);
816
817   FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
818                     observers_,
819                     GattCharacteristicRemoved(this, characteristic));
820 }
821
822 void BluetoothAdapterChromeOS::NotifyGattDescriptorAdded(
823     BluetoothRemoteGattDescriptorChromeOS* descriptor) {
824   DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
825                 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
826             this);
827
828   FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
829                     observers_,
830                     GattDescriptorAdded(this, descriptor));
831 }
832
833 void BluetoothAdapterChromeOS::NotifyGattDescriptorRemoved(
834     BluetoothRemoteGattDescriptorChromeOS* descriptor) {
835   DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
836                 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
837             this);
838
839   FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
840                     observers_,
841                     GattDescriptorRemoved(this, descriptor));
842 }
843
844 void BluetoothAdapterChromeOS::NotifyGattCharacteristicValueChanged(
845     BluetoothRemoteGattCharacteristicChromeOS* characteristic,
846     const std::vector<uint8>& value) {
847   DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
848                 characteristic->GetService())->GetAdapter(),
849             this);
850
851   FOR_EACH_OBSERVER(
852       BluetoothAdapter::Observer,
853       observers_,
854       GattCharacteristicValueChanged(this, characteristic, value));
855 }
856
857 void BluetoothAdapterChromeOS::NotifyGattDescriptorValueChanged(
858     BluetoothRemoteGattDescriptorChromeOS* descriptor,
859     const std::vector<uint8>& value) {
860   DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
861                 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
862             this);
863
864   FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
865                     observers_,
866                     GattDescriptorValueChanged(this, descriptor, value));
867 }
868
869 void BluetoothAdapterChromeOS::OnSetDiscoverable(
870     const base::Closure& callback,
871     const ErrorCallback& error_callback,
872     bool success) {
873   // Set the discoverable_timeout property to zero so the adapter remains
874   // discoverable forever.
875   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
876       GetProperties(object_path_)->discoverable_timeout.Set(
877           0,
878           base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
879                      weak_ptr_factory_.GetWeakPtr(),
880                      callback,
881                      error_callback));
882 }
883
884 void BluetoothAdapterChromeOS::OnPropertyChangeCompleted(
885     const base::Closure& callback,
886     const ErrorCallback& error_callback,
887     bool success) {
888   if (success)
889     callback.Run();
890   else
891     error_callback.Run();
892 }
893
894 void BluetoothAdapterChromeOS::AddDiscoverySession(
895     const base::Closure& callback,
896     const ErrorCallback& error_callback) {
897   VLOG(1) << __func__;
898   if (discovery_request_pending_) {
899     // The pending request is either to stop a previous session or to start a
900     // new one. Either way, queue this one.
901     DCHECK(num_discovery_sessions_ == 1 || num_discovery_sessions_ == 0);
902     VLOG(1) << "Pending request to start/stop device discovery. Queueing "
903             << "request to start a new discovery session.";
904     discovery_request_queue_.push(std::make_pair(callback, error_callback));
905     return;
906   }
907
908   // The adapter is already discovering.
909   if (num_discovery_sessions_ > 0) {
910     DCHECK(IsDiscovering());
911     DCHECK(!discovery_request_pending_);
912     num_discovery_sessions_++;
913     callback.Run();
914     return;
915   }
916
917   // There are no active discovery sessions.
918   DCHECK(num_discovery_sessions_ == 0);
919
920   // This is the first request to start device discovery.
921   discovery_request_pending_ = true;
922   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
923       StartDiscovery(
924           object_path_,
925           base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery,
926                      weak_ptr_factory_.GetWeakPtr(),
927                      callback),
928           base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError,
929                      weak_ptr_factory_.GetWeakPtr(),
930                      callback,
931                      error_callback));
932 }
933
934 void BluetoothAdapterChromeOS::RemoveDiscoverySession(
935     const base::Closure& callback,
936     const ErrorCallback& error_callback) {
937   VLOG(1) << __func__;
938   // There are active sessions other than the one currently being removed.
939   if (num_discovery_sessions_ > 1) {
940     DCHECK(IsDiscovering());
941     DCHECK(!discovery_request_pending_);
942     num_discovery_sessions_--;
943     callback.Run();
944     return;
945   }
946
947   // If there is a pending request to BlueZ, then queue this request.
948   if (discovery_request_pending_) {
949     VLOG(1) << "Pending request to start/stop device discovery. Queueing "
950             << "request to stop discovery session.";
951     error_callback.Run();
952     return;
953   }
954
955   // There are no active sessions. Return error.
956   if (num_discovery_sessions_ == 0) {
957     // TODO(armansito): This should never happen once we have the
958     // DiscoverySession API. Replace this case with an assert once it's
959     // the deprecated methods have been removed. (See crbug.com/3445008).
960     VLOG(1) << "No active discovery sessions. Returning error.";
961     error_callback.Run();
962     return;
963   }
964
965   // There is exactly one active discovery session. Request BlueZ to stop
966   // discovery.
967   DCHECK(num_discovery_sessions_ == 1);
968   discovery_request_pending_ = true;
969   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
970       StopDiscovery(
971           object_path_,
972           base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery,
973                      weak_ptr_factory_.GetWeakPtr(),
974                      callback),
975           base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError,
976                      weak_ptr_factory_.GetWeakPtr(),
977                      error_callback));
978 }
979
980 void BluetoothAdapterChromeOS::OnStartDiscovery(const base::Closure& callback) {
981   // Report success on the original request and increment the count.
982   VLOG(1) << __func__;
983   DCHECK(discovery_request_pending_);
984   DCHECK(num_discovery_sessions_ == 0);
985   discovery_request_pending_ = false;
986   num_discovery_sessions_++;
987   callback.Run();
988
989   // Try to add a new discovery session for each queued request.
990   ProcessQueuedDiscoveryRequests();
991 }
992
993 void BluetoothAdapterChromeOS::OnStartDiscoveryError(
994     const base::Closure& callback,
995     const ErrorCallback& error_callback,
996     const std::string& error_name,
997     const std::string& error_message) {
998   LOG(WARNING) << object_path_.value() << ": Failed to start discovery: "
999                << error_name << ": " << error_message;
1000
1001   // Failed to start discovery. This can only happen if the count is at 0.
1002   DCHECK(num_discovery_sessions_ == 0);
1003   DCHECK(discovery_request_pending_);
1004   discovery_request_pending_ = false;
1005
1006   // Discovery request may fail if discovery was previously initiated by Chrome,
1007   // but the session were invalidated due to the discovery state unexpectedly
1008   // changing to false and then back to true. In this case, report success.
1009   if (error_name == bluetooth_device::kErrorInProgress && IsDiscovering()) {
1010     VLOG(1) << "Discovery previously initiated. Reporting success.";
1011     num_discovery_sessions_++;
1012     callback.Run();
1013   } else {
1014     error_callback.Run();
1015   }
1016
1017   // Try to add a new discovery session for each queued request.
1018   ProcessQueuedDiscoveryRequests();
1019 }
1020
1021 void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure& callback) {
1022   // Report success on the original request and decrement the count.
1023   VLOG(1) << __func__;
1024   DCHECK(discovery_request_pending_);
1025   DCHECK(num_discovery_sessions_ == 1);
1026   discovery_request_pending_ = false;
1027   num_discovery_sessions_--;
1028   callback.Run();
1029
1030   // Try to add a new discovery session for each queued request.
1031   ProcessQueuedDiscoveryRequests();
1032 }
1033
1034 void BluetoothAdapterChromeOS::OnStopDiscoveryError(
1035     const ErrorCallback& error_callback,
1036     const std::string& error_name,
1037     const std::string& error_message) {
1038   LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: "
1039                << error_name << ": " << error_message;
1040
1041   // Failed to stop discovery. This can only happen if the count is at 1.
1042   DCHECK(discovery_request_pending_);
1043   DCHECK(num_discovery_sessions_ == 1);
1044   discovery_request_pending_ = false;
1045   error_callback.Run();
1046
1047   // Try to add a new discovery session for each queued request.
1048   ProcessQueuedDiscoveryRequests();
1049 }
1050
1051 void BluetoothAdapterChromeOS::ProcessQueuedDiscoveryRequests() {
1052   while (!discovery_request_queue_.empty()) {
1053     VLOG(1) << "Process queued discovery request.";
1054     DiscoveryCallbackPair callbacks = discovery_request_queue_.front();
1055     discovery_request_queue_.pop();
1056     AddDiscoverySession(callbacks.first, callbacks.second);
1057
1058     // If the queued request resulted in a pending call, then let it
1059     // asynchonously process the remaining queued requests once the pending
1060     // call returns.
1061     if (discovery_request_pending_)
1062       return;
1063   }
1064 }
1065
1066 }  // namespace chromeos