OLD | NEW |
| (Empty) |
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_device_chromeos.h" | |
6 | |
7 #include <stdio.h> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/memory/scoped_ptr.h" | |
11 #include "base/metrics/histogram.h" | |
12 #include "base/strings/string_number_conversions.h" | |
13 #include "base/strings/string_util.h" | |
14 #include "dbus/bus.h" | |
15 #include "device/bluetooth/bluetooth_adapter_chromeos.h" | |
16 #include "device/bluetooth/bluetooth_gatt_connection_chromeos.h" | |
17 #include "device/bluetooth/bluetooth_pairing_chromeos.h" | |
18 #include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h" | |
19 #include "device/bluetooth/bluetooth_socket.h" | |
20 #include "device/bluetooth/bluetooth_socket_chromeos.h" | |
21 #include "device/bluetooth/bluetooth_socket_thread.h" | |
22 #include "device/bluetooth/bluetooth_uuid.h" | |
23 #include "device/bluetooth/dbus/bluetooth_adapter_client.h" | |
24 #include "device/bluetooth/dbus/bluetooth_device_client.h" | |
25 #include "device/bluetooth/dbus/bluetooth_gatt_service_client.h" | |
26 #include "device/bluetooth/dbus/bluetooth_input_client.h" | |
27 #include "device/bluetooth/dbus/bluez_dbus_manager.h" | |
28 #include "third_party/cros_system_api/dbus/service_constants.h" | |
29 | |
30 using device::BluetoothDevice; | |
31 using device::BluetoothGattService; | |
32 using device::BluetoothSocket; | |
33 using device::BluetoothUUID; | |
34 | |
35 namespace { | |
36 | |
37 // Histogram enumerations for pairing results. | |
38 enum UMAPairingResult { | |
39 UMA_PAIRING_RESULT_SUCCESS, | |
40 UMA_PAIRING_RESULT_INPROGRESS, | |
41 UMA_PAIRING_RESULT_FAILED, | |
42 UMA_PAIRING_RESULT_AUTH_FAILED, | |
43 UMA_PAIRING_RESULT_AUTH_CANCELED, | |
44 UMA_PAIRING_RESULT_AUTH_REJECTED, | |
45 UMA_PAIRING_RESULT_AUTH_TIMEOUT, | |
46 UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE, | |
47 UMA_PAIRING_RESULT_UNKNOWN_ERROR, | |
48 // NOTE: Add new pairing results immediately above this line. Make sure to | |
49 // update the enum list in tools/histogram/histograms.xml accordinly. | |
50 UMA_PAIRING_RESULT_COUNT | |
51 }; | |
52 | |
53 void ParseModalias(const dbus::ObjectPath& object_path, | |
54 BluetoothDevice::VendorIDSource* vendor_id_source, | |
55 uint16* vendor_id, | |
56 uint16* product_id, | |
57 uint16* device_id) { | |
58 bluez::BluetoothDeviceClient::Properties* properties = | |
59 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
60 object_path); | |
61 DCHECK(properties); | |
62 | |
63 std::string modalias = properties->modalias.value(); | |
64 BluetoothDevice::VendorIDSource source_value; | |
65 int vendor_value, product_value, device_value; | |
66 | |
67 if (sscanf(modalias.c_str(), "bluetooth:v%04xp%04xd%04x", | |
68 &vendor_value, &product_value, &device_value) == 3) { | |
69 source_value = BluetoothDevice::VENDOR_ID_BLUETOOTH; | |
70 } else if (sscanf(modalias.c_str(), "usb:v%04xp%04xd%04x", | |
71 &vendor_value, &product_value, &device_value) == 3) { | |
72 source_value = BluetoothDevice::VENDOR_ID_USB; | |
73 } else { | |
74 return; | |
75 } | |
76 | |
77 if (vendor_id_source != NULL) | |
78 *vendor_id_source = source_value; | |
79 if (vendor_id != NULL) | |
80 *vendor_id = vendor_value; | |
81 if (product_id != NULL) | |
82 *product_id = product_value; | |
83 if (device_id != NULL) | |
84 *device_id = device_value; | |
85 } | |
86 | |
87 void RecordPairingResult(BluetoothDevice::ConnectErrorCode error_code) { | |
88 UMAPairingResult pairing_result; | |
89 switch (error_code) { | |
90 case BluetoothDevice::ERROR_INPROGRESS: | |
91 pairing_result = UMA_PAIRING_RESULT_INPROGRESS; | |
92 break; | |
93 case BluetoothDevice::ERROR_FAILED: | |
94 pairing_result = UMA_PAIRING_RESULT_FAILED; | |
95 break; | |
96 case BluetoothDevice::ERROR_AUTH_FAILED: | |
97 pairing_result = UMA_PAIRING_RESULT_AUTH_FAILED; | |
98 break; | |
99 case BluetoothDevice::ERROR_AUTH_CANCELED: | |
100 pairing_result = UMA_PAIRING_RESULT_AUTH_CANCELED; | |
101 break; | |
102 case BluetoothDevice::ERROR_AUTH_REJECTED: | |
103 pairing_result = UMA_PAIRING_RESULT_AUTH_REJECTED; | |
104 break; | |
105 case BluetoothDevice::ERROR_AUTH_TIMEOUT: | |
106 pairing_result = UMA_PAIRING_RESULT_AUTH_TIMEOUT; | |
107 break; | |
108 case BluetoothDevice::ERROR_UNSUPPORTED_DEVICE: | |
109 pairing_result = UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE; | |
110 break; | |
111 default: | |
112 pairing_result = UMA_PAIRING_RESULT_UNKNOWN_ERROR; | |
113 } | |
114 | |
115 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult", | |
116 pairing_result, | |
117 UMA_PAIRING_RESULT_COUNT); | |
118 } | |
119 | |
120 BluetoothDevice::ConnectErrorCode DBusErrorToConnectError( | |
121 const std::string& error_name) { | |
122 BluetoothDevice::ConnectErrorCode error_code = BluetoothDevice::ERROR_UNKNOWN; | |
123 if (error_name == bluetooth_device::kErrorConnectionAttemptFailed) { | |
124 error_code = BluetoothDevice::ERROR_FAILED; | |
125 } else if (error_name == bluetooth_device::kErrorFailed) { | |
126 error_code = BluetoothDevice::ERROR_FAILED; | |
127 } else if (error_name == bluetooth_device::kErrorAuthenticationFailed) { | |
128 error_code = BluetoothDevice::ERROR_AUTH_FAILED; | |
129 } else if (error_name == bluetooth_device::kErrorAuthenticationCanceled) { | |
130 error_code = BluetoothDevice::ERROR_AUTH_CANCELED; | |
131 } else if (error_name == bluetooth_device::kErrorAuthenticationRejected) { | |
132 error_code = BluetoothDevice::ERROR_AUTH_REJECTED; | |
133 } else if (error_name == bluetooth_device::kErrorAuthenticationTimeout) { | |
134 error_code = BluetoothDevice::ERROR_AUTH_TIMEOUT; | |
135 } | |
136 return error_code; | |
137 } | |
138 | |
139 } // namespace | |
140 | |
141 namespace chromeos { | |
142 | |
143 BluetoothDeviceChromeOS::BluetoothDeviceChromeOS( | |
144 BluetoothAdapterChromeOS* adapter, | |
145 const dbus::ObjectPath& object_path, | |
146 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, | |
147 scoped_refptr<device::BluetoothSocketThread> socket_thread) | |
148 : BluetoothDevice(adapter), | |
149 object_path_(object_path), | |
150 num_connecting_calls_(0), | |
151 connection_monitor_started_(false), | |
152 ui_task_runner_(ui_task_runner), | |
153 socket_thread_(socket_thread), | |
154 weak_ptr_factory_(this) { | |
155 bluez::BluezDBusManager::Get()->GetBluetoothGattServiceClient()->AddObserver( | |
156 this); | |
157 | |
158 // Add all known GATT services. | |
159 const std::vector<dbus::ObjectPath> gatt_services = | |
160 bluez::BluezDBusManager::Get() | |
161 ->GetBluetoothGattServiceClient() | |
162 ->GetServices(); | |
163 for (std::vector<dbus::ObjectPath>::const_iterator it = gatt_services.begin(); | |
164 it != gatt_services.end(); ++it) { | |
165 GattServiceAdded(*it); | |
166 } | |
167 } | |
168 | |
169 BluetoothDeviceChromeOS::~BluetoothDeviceChromeOS() { | |
170 bluez::BluezDBusManager::Get() | |
171 ->GetBluetoothGattServiceClient() | |
172 ->RemoveObserver(this); | |
173 | |
174 // Copy the GATT services list here and clear the original so that when we | |
175 // send GattServiceRemoved(), GetGattServices() returns no services. | |
176 GattServiceMap gatt_services_swapped; | |
177 gatt_services_swapped.swap(gatt_services_); | |
178 for (const auto& iter : gatt_services_swapped) { | |
179 DCHECK(adapter_); | |
180 adapter()->NotifyGattServiceRemoved( | |
181 static_cast<BluetoothRemoteGattServiceChromeOS*>(iter.second)); | |
182 } | |
183 } | |
184 | |
185 uint32 BluetoothDeviceChromeOS::GetBluetoothClass() const { | |
186 bluez::BluetoothDeviceClient::Properties* properties = | |
187 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
188 object_path_); | |
189 DCHECK(properties); | |
190 | |
191 return properties->bluetooth_class.value(); | |
192 } | |
193 | |
194 std::string BluetoothDeviceChromeOS::GetDeviceName() const { | |
195 bluez::BluetoothDeviceClient::Properties* properties = | |
196 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
197 object_path_); | |
198 DCHECK(properties); | |
199 | |
200 return properties->alias.value(); | |
201 } | |
202 | |
203 void BluetoothDeviceChromeOS::CreateGattConnectionImpl() { | |
204 // ChromeOS implementation does not use the default CreateGattConnection | |
205 // implementation. | |
206 NOTIMPLEMENTED(); | |
207 } | |
208 | |
209 void BluetoothDeviceChromeOS::DisconnectGatt() { | |
210 // ChromeOS implementation does not use the default CreateGattConnection | |
211 // implementation. | |
212 NOTIMPLEMENTED(); | |
213 } | |
214 | |
215 std::string BluetoothDeviceChromeOS::GetAddress() const { | |
216 bluez::BluetoothDeviceClient::Properties* properties = | |
217 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
218 object_path_); | |
219 DCHECK(properties); | |
220 | |
221 return CanonicalizeAddress(properties->address.value()); | |
222 } | |
223 | |
224 BluetoothDevice::VendorIDSource | |
225 BluetoothDeviceChromeOS::GetVendorIDSource() const { | |
226 VendorIDSource vendor_id_source = VENDOR_ID_UNKNOWN; | |
227 ParseModalias(object_path_, &vendor_id_source, NULL, NULL, NULL); | |
228 return vendor_id_source; | |
229 } | |
230 | |
231 uint16 BluetoothDeviceChromeOS::GetVendorID() const { | |
232 uint16 vendor_id = 0; | |
233 ParseModalias(object_path_, NULL, &vendor_id, NULL, NULL); | |
234 return vendor_id; | |
235 } | |
236 | |
237 uint16 BluetoothDeviceChromeOS::GetProductID() const { | |
238 uint16 product_id = 0; | |
239 ParseModalias(object_path_, NULL, NULL, &product_id, NULL); | |
240 return product_id; | |
241 } | |
242 | |
243 uint16 BluetoothDeviceChromeOS::GetDeviceID() const { | |
244 uint16 device_id = 0; | |
245 ParseModalias(object_path_, NULL, NULL, NULL, &device_id); | |
246 return device_id; | |
247 } | |
248 | |
249 bool BluetoothDeviceChromeOS::IsPaired() const { | |
250 bluez::BluetoothDeviceClient::Properties* properties = | |
251 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
252 object_path_); | |
253 DCHECK(properties); | |
254 | |
255 // Trusted devices are devices that don't support pairing but that the | |
256 // user has explicitly connected; it makes no sense for UI purposes to | |
257 // treat them differently from each other. | |
258 return properties->paired.value() || properties->trusted.value(); | |
259 } | |
260 | |
261 bool BluetoothDeviceChromeOS::IsConnected() const { | |
262 bluez::BluetoothDeviceClient::Properties* properties = | |
263 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
264 object_path_); | |
265 DCHECK(properties); | |
266 | |
267 return properties->connected.value(); | |
268 } | |
269 | |
270 bool BluetoothDeviceChromeOS::IsGattConnected() const { | |
271 NOTIMPLEMENTED(); | |
272 return false; | |
273 } | |
274 | |
275 bool BluetoothDeviceChromeOS::IsConnectable() const { | |
276 bluez::BluetoothInputClient::Properties* input_properties = | |
277 bluez::BluezDBusManager::Get()->GetBluetoothInputClient()->GetProperties( | |
278 object_path_); | |
279 // GetProperties returns NULL when the device does not implement the given | |
280 // interface. Non HID devices are normally connectable. | |
281 if (!input_properties) | |
282 return true; | |
283 | |
284 return input_properties->reconnect_mode.value() != "device"; | |
285 } | |
286 | |
287 bool BluetoothDeviceChromeOS::IsConnecting() const { | |
288 return num_connecting_calls_ > 0; | |
289 } | |
290 | |
291 BluetoothDeviceChromeOS::UUIDList BluetoothDeviceChromeOS::GetUUIDs() const { | |
292 bluez::BluetoothDeviceClient::Properties* properties = | |
293 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
294 object_path_); | |
295 DCHECK(properties); | |
296 | |
297 std::vector<device::BluetoothUUID> uuids; | |
298 const std::vector<std::string> &dbus_uuids = properties->uuids.value(); | |
299 for (std::vector<std::string>::const_iterator iter = dbus_uuids.begin(); | |
300 iter != dbus_uuids.end(); ++iter) { | |
301 device::BluetoothUUID uuid(*iter); | |
302 DCHECK(uuid.IsValid()); | |
303 uuids.push_back(uuid); | |
304 } | |
305 return uuids; | |
306 } | |
307 | |
308 int16 BluetoothDeviceChromeOS::GetInquiryRSSI() const { | |
309 bluez::BluetoothDeviceClient::Properties* properties = | |
310 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
311 object_path_); | |
312 DCHECK(properties); | |
313 | |
314 if (!properties->rssi.is_valid()) | |
315 return kUnknownPower; | |
316 | |
317 return properties->rssi.value(); | |
318 } | |
319 | |
320 int16 BluetoothDeviceChromeOS::GetInquiryTxPower() const { | |
321 bluez::BluetoothDeviceClient::Properties* properties = | |
322 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
323 object_path_); | |
324 DCHECK(properties); | |
325 | |
326 if (!properties->tx_power.is_valid()) | |
327 return kUnknownPower; | |
328 | |
329 return properties->tx_power.value(); | |
330 } | |
331 | |
332 bool BluetoothDeviceChromeOS::ExpectingPinCode() const { | |
333 return pairing_.get() && pairing_->ExpectingPinCode(); | |
334 } | |
335 | |
336 bool BluetoothDeviceChromeOS::ExpectingPasskey() const { | |
337 return pairing_.get() && pairing_->ExpectingPasskey(); | |
338 } | |
339 | |
340 bool BluetoothDeviceChromeOS::ExpectingConfirmation() const { | |
341 return pairing_.get() && pairing_->ExpectingConfirmation(); | |
342 } | |
343 | |
344 void BluetoothDeviceChromeOS::GetConnectionInfo( | |
345 const ConnectionInfoCallback& callback) { | |
346 // DBus method call should gracefully return an error if the device is not | |
347 // currently connected. | |
348 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetConnInfo( | |
349 object_path_, base::Bind(&BluetoothDeviceChromeOS::OnGetConnInfo, | |
350 weak_ptr_factory_.GetWeakPtr(), callback), | |
351 base::Bind(&BluetoothDeviceChromeOS::OnGetConnInfoError, | |
352 weak_ptr_factory_.GetWeakPtr(), callback)); | |
353 } | |
354 | |
355 void BluetoothDeviceChromeOS::Connect( | |
356 BluetoothDevice::PairingDelegate* pairing_delegate, | |
357 const base::Closure& callback, | |
358 const ConnectErrorCallback& error_callback) { | |
359 if (num_connecting_calls_++ == 0) | |
360 adapter()->NotifyDeviceChanged(this); | |
361 | |
362 VLOG(1) << object_path_.value() << ": Connecting, " << num_connecting_calls_ | |
363 << " in progress"; | |
364 | |
365 if (IsPaired() || !pairing_delegate || !IsPairable()) { | |
366 // No need to pair, or unable to, skip straight to connection. | |
367 ConnectInternal(false, callback, error_callback); | |
368 } else { | |
369 // Initiate high-security connection with pairing. | |
370 BeginPairing(pairing_delegate); | |
371 | |
372 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->Pair( | |
373 object_path_, | |
374 base::Bind(&BluetoothDeviceChromeOS::OnPairDuringConnect, | |
375 weak_ptr_factory_.GetWeakPtr(), callback, error_callback), | |
376 base::Bind(&BluetoothDeviceChromeOS::OnPairDuringConnectError, | |
377 weak_ptr_factory_.GetWeakPtr(), error_callback)); | |
378 } | |
379 } | |
380 | |
381 void BluetoothDeviceChromeOS::Pair( | |
382 BluetoothDevice::PairingDelegate* pairing_delegate, | |
383 const base::Closure& callback, | |
384 const ConnectErrorCallback& error_callback) { | |
385 DCHECK(pairing_delegate); | |
386 BeginPairing(pairing_delegate); | |
387 | |
388 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->Pair( | |
389 object_path_, base::Bind(&BluetoothDeviceChromeOS::OnPair, | |
390 weak_ptr_factory_.GetWeakPtr(), callback), | |
391 base::Bind(&BluetoothDeviceChromeOS::OnPairError, | |
392 weak_ptr_factory_.GetWeakPtr(), error_callback)); | |
393 } | |
394 | |
395 void BluetoothDeviceChromeOS::SetPinCode(const std::string& pincode) { | |
396 if (!pairing_.get()) | |
397 return; | |
398 | |
399 pairing_->SetPinCode(pincode); | |
400 } | |
401 | |
402 void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) { | |
403 if (!pairing_.get()) | |
404 return; | |
405 | |
406 pairing_->SetPasskey(passkey); | |
407 } | |
408 | |
409 void BluetoothDeviceChromeOS::ConfirmPairing() { | |
410 if (!pairing_.get()) | |
411 return; | |
412 | |
413 pairing_->ConfirmPairing(); | |
414 } | |
415 | |
416 void BluetoothDeviceChromeOS::RejectPairing() { | |
417 if (!pairing_.get()) | |
418 return; | |
419 | |
420 pairing_->RejectPairing(); | |
421 } | |
422 | |
423 void BluetoothDeviceChromeOS::CancelPairing() { | |
424 bool canceled = false; | |
425 | |
426 // If there is a callback in progress that we can reply to then use that | |
427 // to cancel the current pairing request. | |
428 if (pairing_.get() && pairing_->CancelPairing()) | |
429 canceled = true; | |
430 | |
431 // If not we have to send an explicit CancelPairing() to the device instead. | |
432 if (!canceled) { | |
433 VLOG(1) << object_path_.value() << ": No pairing context or callback. " | |
434 << "Sending explicit cancel"; | |
435 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->CancelPairing( | |
436 object_path_, base::Bind(&base::DoNothing), | |
437 base::Bind(&BluetoothDeviceChromeOS::OnCancelPairingError, | |
438 weak_ptr_factory_.GetWeakPtr())); | |
439 } | |
440 | |
441 // Since there is no callback to this method it's possible that the pairing | |
442 // delegate is going to be freed before things complete (indeed it's | |
443 // documented that this is the method you should call while freeing the | |
444 // pairing delegate), so clear our the context holding on to it. | |
445 EndPairing(); | |
446 } | |
447 | |
448 void BluetoothDeviceChromeOS::Disconnect(const base::Closure& callback, | |
449 const ErrorCallback& error_callback) { | |
450 VLOG(1) << object_path_.value() << ": Disconnecting"; | |
451 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->Disconnect( | |
452 object_path_, base::Bind(&BluetoothDeviceChromeOS::OnDisconnect, | |
453 weak_ptr_factory_.GetWeakPtr(), callback), | |
454 base::Bind(&BluetoothDeviceChromeOS::OnDisconnectError, | |
455 weak_ptr_factory_.GetWeakPtr(), error_callback)); | |
456 } | |
457 | |
458 void BluetoothDeviceChromeOS::Forget(const ErrorCallback& error_callback) { | |
459 VLOG(1) << object_path_.value() << ": Removing device"; | |
460 bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient()->RemoveDevice( | |
461 adapter()->object_path(), object_path_, base::Bind(&base::DoNothing), | |
462 base::Bind(&BluetoothDeviceChromeOS::OnForgetError, | |
463 weak_ptr_factory_.GetWeakPtr(), error_callback)); | |
464 } | |
465 | |
466 void BluetoothDeviceChromeOS::ConnectToService( | |
467 const BluetoothUUID& uuid, | |
468 const ConnectToServiceCallback& callback, | |
469 const ConnectToServiceErrorCallback& error_callback) { | |
470 VLOG(1) << object_path_.value() << ": Connecting to service: " | |
471 << uuid.canonical_value(); | |
472 scoped_refptr<BluetoothSocketChromeOS> socket = | |
473 BluetoothSocketChromeOS::CreateBluetoothSocket( | |
474 ui_task_runner_, socket_thread_); | |
475 socket->Connect(this, uuid, BluetoothSocketChromeOS::SECURITY_LEVEL_MEDIUM, | |
476 base::Bind(callback, socket), error_callback); | |
477 } | |
478 | |
479 void BluetoothDeviceChromeOS::ConnectToServiceInsecurely( | |
480 const BluetoothUUID& uuid, | |
481 const ConnectToServiceCallback& callback, | |
482 const ConnectToServiceErrorCallback& error_callback) { | |
483 VLOG(1) << object_path_.value() << ": Connecting insecurely to service: " | |
484 << uuid.canonical_value(); | |
485 scoped_refptr<BluetoothSocketChromeOS> socket = | |
486 BluetoothSocketChromeOS::CreateBluetoothSocket( | |
487 ui_task_runner_, socket_thread_); | |
488 socket->Connect(this, uuid, BluetoothSocketChromeOS::SECURITY_LEVEL_LOW, | |
489 base::Bind(callback, socket), error_callback); | |
490 } | |
491 | |
492 void BluetoothDeviceChromeOS::CreateGattConnection( | |
493 const GattConnectionCallback& callback, | |
494 const ConnectErrorCallback& error_callback) { | |
495 // TODO(sacomoto): Workaround to retrieve the connection for already connected | |
496 // devices. Currently, BluetoothGattConnection::Disconnect doesn't do | |
497 // anything, the unique underlying physical GATT connection is kept. This | |
498 // should be removed once the correct behavour is implemented and the GATT | |
499 // connections are reference counted (see todo below). | |
500 if (IsConnected()) { | |
501 OnCreateGattConnection(callback); | |
502 return; | |
503 } | |
504 | |
505 // TODO(armansito): Until there is a way to create a reference counted GATT | |
506 // connection in bluetoothd, simply do a regular connect. | |
507 Connect(NULL, | |
508 base::Bind(&BluetoothDeviceChromeOS::OnCreateGattConnection, | |
509 weak_ptr_factory_.GetWeakPtr(), | |
510 callback), | |
511 error_callback); | |
512 } | |
513 | |
514 BluetoothPairingChromeOS* BluetoothDeviceChromeOS::BeginPairing( | |
515 BluetoothDevice::PairingDelegate* pairing_delegate) { | |
516 pairing_.reset(new BluetoothPairingChromeOS(this, pairing_delegate)); | |
517 return pairing_.get(); | |
518 } | |
519 | |
520 void BluetoothDeviceChromeOS::EndPairing() { | |
521 pairing_.reset(); | |
522 } | |
523 | |
524 BluetoothPairingChromeOS* BluetoothDeviceChromeOS::GetPairing() const { | |
525 return pairing_.get(); | |
526 } | |
527 | |
528 BluetoothAdapterChromeOS* BluetoothDeviceChromeOS::adapter() const { | |
529 return static_cast<BluetoothAdapterChromeOS*>(adapter_); | |
530 } | |
531 | |
532 void BluetoothDeviceChromeOS::GattServiceAdded( | |
533 const dbus::ObjectPath& object_path) { | |
534 if (GetGattService(object_path.value())) { | |
535 VLOG(1) << "Remote GATT service already exists: " << object_path.value(); | |
536 return; | |
537 } | |
538 | |
539 bluez::BluetoothGattServiceClient::Properties* properties = | |
540 bluez::BluezDBusManager::Get() | |
541 ->GetBluetoothGattServiceClient() | |
542 ->GetProperties(object_path); | |
543 DCHECK(properties); | |
544 if (properties->device.value() != object_path_) { | |
545 VLOG(2) << "Remote GATT service does not belong to this device."; | |
546 return; | |
547 } | |
548 | |
549 VLOG(1) << "Adding new remote GATT service for device: " << GetAddress(); | |
550 | |
551 BluetoothRemoteGattServiceChromeOS* service = | |
552 new BluetoothRemoteGattServiceChromeOS(adapter(), this, object_path); | |
553 | |
554 gatt_services_.set(service->GetIdentifier(), | |
555 scoped_ptr<BluetoothGattService>(service)); | |
556 DCHECK(service->object_path() == object_path); | |
557 DCHECK(service->GetUUID().IsValid()); | |
558 | |
559 DCHECK(adapter_); | |
560 adapter()->NotifyGattServiceAdded(service); | |
561 } | |
562 | |
563 void BluetoothDeviceChromeOS::GattServiceRemoved( | |
564 const dbus::ObjectPath& object_path) { | |
565 GattServiceMap::const_iterator iter = | |
566 gatt_services_.find(object_path.value()); | |
567 if (iter == gatt_services_.end()) { | |
568 VLOG(3) << "Unknown GATT service removed: " << object_path.value(); | |
569 return; | |
570 } | |
571 | |
572 BluetoothRemoteGattServiceChromeOS* service = | |
573 static_cast<BluetoothRemoteGattServiceChromeOS*>(iter->second); | |
574 | |
575 VLOG(1) << "Removing remote GATT service with UUID: '" | |
576 << service->GetUUID().canonical_value() | |
577 << "' from device: " << GetAddress(); | |
578 | |
579 DCHECK(service->object_path() == object_path); | |
580 scoped_ptr<BluetoothGattService> scoped_service = | |
581 gatt_services_.take_and_erase(iter->first); | |
582 | |
583 DCHECK(adapter_); | |
584 adapter()->NotifyGattServiceRemoved(service); | |
585 } | |
586 | |
587 void BluetoothDeviceChromeOS::OnGetConnInfo( | |
588 const ConnectionInfoCallback& callback, | |
589 int16 rssi, | |
590 int16 transmit_power, | |
591 int16 max_transmit_power) { | |
592 callback.Run(ConnectionInfo(rssi, transmit_power, max_transmit_power)); | |
593 } | |
594 | |
595 void BluetoothDeviceChromeOS::OnGetConnInfoError( | |
596 const ConnectionInfoCallback& callback, | |
597 const std::string& error_name, | |
598 const std::string& error_message) { | |
599 LOG(WARNING) << object_path_.value() | |
600 << ": Failed to get connection info: " << error_name << ": " | |
601 << error_message; | |
602 callback.Run(ConnectionInfo()); | |
603 } | |
604 | |
605 void BluetoothDeviceChromeOS::ConnectInternal( | |
606 bool after_pairing, | |
607 const base::Closure& callback, | |
608 const ConnectErrorCallback& error_callback) { | |
609 VLOG(1) << object_path_.value() << ": Connecting"; | |
610 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->Connect( | |
611 object_path_, | |
612 base::Bind(&BluetoothDeviceChromeOS::OnConnect, | |
613 weak_ptr_factory_.GetWeakPtr(), after_pairing, callback), | |
614 base::Bind(&BluetoothDeviceChromeOS::OnConnectError, | |
615 weak_ptr_factory_.GetWeakPtr(), after_pairing, | |
616 error_callback)); | |
617 } | |
618 | |
619 void BluetoothDeviceChromeOS::OnConnect(bool after_pairing, | |
620 const base::Closure& callback) { | |
621 if (--num_connecting_calls_ == 0) | |
622 adapter()->NotifyDeviceChanged(this); | |
623 | |
624 DCHECK(num_connecting_calls_ >= 0); | |
625 VLOG(1) << object_path_.value() << ": Connected, " << num_connecting_calls_ | |
626 << " still in progress"; | |
627 | |
628 SetTrusted(); | |
629 | |
630 if (after_pairing) | |
631 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult", | |
632 UMA_PAIRING_RESULT_SUCCESS, | |
633 UMA_PAIRING_RESULT_COUNT); | |
634 | |
635 callback.Run(); | |
636 } | |
637 | |
638 void BluetoothDeviceChromeOS::OnCreateGattConnection( | |
639 const GattConnectionCallback& callback) { | |
640 scoped_ptr<device::BluetoothGattConnection> conn( | |
641 new BluetoothGattConnectionChromeOS( | |
642 adapter_, GetAddress(), object_path_)); | |
643 callback.Run(conn.Pass()); | |
644 } | |
645 | |
646 void BluetoothDeviceChromeOS::OnConnectError( | |
647 bool after_pairing, | |
648 const ConnectErrorCallback& error_callback, | |
649 const std::string& error_name, | |
650 const std::string& error_message) { | |
651 if (--num_connecting_calls_ == 0) | |
652 adapter()->NotifyDeviceChanged(this); | |
653 | |
654 DCHECK(num_connecting_calls_ >= 0); | |
655 LOG(WARNING) << object_path_.value() << ": Failed to connect device: " | |
656 << error_name << ": " << error_message; | |
657 VLOG(1) << object_path_.value() << ": " << num_connecting_calls_ | |
658 << " still in progress"; | |
659 | |
660 // Determine the error code from error_name. | |
661 ConnectErrorCode error_code = ERROR_UNKNOWN; | |
662 if (error_name == bluetooth_device::kErrorFailed) { | |
663 error_code = ERROR_FAILED; | |
664 } else if (error_name == bluetooth_device::kErrorInProgress) { | |
665 error_code = ERROR_INPROGRESS; | |
666 } else if (error_name == bluetooth_device::kErrorNotSupported) { | |
667 error_code = ERROR_UNSUPPORTED_DEVICE; | |
668 } | |
669 | |
670 if (after_pairing) | |
671 RecordPairingResult(error_code); | |
672 error_callback.Run(error_code); | |
673 } | |
674 | |
675 void BluetoothDeviceChromeOS::OnPairDuringConnect( | |
676 const base::Closure& callback, | |
677 const ConnectErrorCallback& error_callback) { | |
678 VLOG(1) << object_path_.value() << ": Paired"; | |
679 | |
680 EndPairing(); | |
681 | |
682 ConnectInternal(true, callback, error_callback); | |
683 } | |
684 | |
685 void BluetoothDeviceChromeOS::OnPairDuringConnectError( | |
686 const ConnectErrorCallback& error_callback, | |
687 const std::string& error_name, | |
688 const std::string& error_message) { | |
689 if (--num_connecting_calls_ == 0) | |
690 adapter()->NotifyDeviceChanged(this); | |
691 | |
692 DCHECK(num_connecting_calls_ >= 0); | |
693 LOG(WARNING) << object_path_.value() << ": Failed to pair device: " | |
694 << error_name << ": " << error_message; | |
695 VLOG(1) << object_path_.value() << ": " << num_connecting_calls_ | |
696 << " still in progress"; | |
697 | |
698 EndPairing(); | |
699 | |
700 // Determine the error code from error_name. | |
701 ConnectErrorCode error_code = DBusErrorToConnectError(error_name); | |
702 | |
703 RecordPairingResult(error_code); | |
704 error_callback.Run(error_code); | |
705 } | |
706 | |
707 void BluetoothDeviceChromeOS::OnPair(const base::Closure& callback) { | |
708 VLOG(1) << object_path_.value() << ": Paired"; | |
709 EndPairing(); | |
710 callback.Run(); | |
711 } | |
712 | |
713 void BluetoothDeviceChromeOS::OnPairError( | |
714 const ConnectErrorCallback& error_callback, | |
715 const std::string& error_name, | |
716 const std::string& error_message) { | |
717 LOG(WARNING) << object_path_.value() | |
718 << ": Failed to pair device: " << error_name << ": " | |
719 << error_message; | |
720 EndPairing(); | |
721 ConnectErrorCode error_code = DBusErrorToConnectError(error_name); | |
722 RecordPairingResult(error_code); | |
723 error_callback.Run(error_code); | |
724 } | |
725 | |
726 void BluetoothDeviceChromeOS::OnCancelPairingError( | |
727 const std::string& error_name, | |
728 const std::string& error_message) { | |
729 LOG(WARNING) << object_path_.value() << ": Failed to cancel pairing: " | |
730 << error_name << ": " << error_message; | |
731 } | |
732 | |
733 void BluetoothDeviceChromeOS::SetTrusted() { | |
734 // Unconditionally send the property change, rather than checking the value | |
735 // first; there's no harm in doing this and it solves any race conditions | |
736 // with the property becoming true or false and this call happening before | |
737 // we get the D-Bus signal about the earlier change. | |
738 bluez::BluezDBusManager::Get() | |
739 ->GetBluetoothDeviceClient() | |
740 ->GetProperties(object_path_) | |
741 ->trusted.Set(true, base::Bind(&BluetoothDeviceChromeOS::OnSetTrusted, | |
742 weak_ptr_factory_.GetWeakPtr())); | |
743 } | |
744 | |
745 void BluetoothDeviceChromeOS::OnSetTrusted(bool success) { | |
746 LOG_IF(WARNING, !success) << object_path_.value() | |
747 << ": Failed to set device as trusted"; | |
748 } | |
749 | |
750 void BluetoothDeviceChromeOS::OnDisconnect(const base::Closure& callback) { | |
751 VLOG(1) << object_path_.value() << ": Disconnected"; | |
752 callback.Run(); | |
753 } | |
754 | |
755 void BluetoothDeviceChromeOS::OnDisconnectError( | |
756 const ErrorCallback& error_callback, | |
757 const std::string& error_name, | |
758 const std::string& error_message) { | |
759 LOG(WARNING) << object_path_.value() << ": Failed to disconnect device: " | |
760 << error_name << ": " << error_message; | |
761 error_callback.Run(); | |
762 } | |
763 | |
764 void BluetoothDeviceChromeOS::OnForgetError( | |
765 const ErrorCallback& error_callback, | |
766 const std::string& error_name, | |
767 const std::string& error_message) { | |
768 LOG(WARNING) << object_path_.value() << ": Failed to remove device: " | |
769 << error_name << ": " << error_message; | |
770 error_callback.Run(); | |
771 } | |
772 | |
773 } // namespace chromeos | |
OLD | NEW |