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