1 // Copyright (c) 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.
5 #include "device/bluetooth/bluetooth_device_experimental_chromeos.h"
8 #include "base/metrics/histogram.h"
9 #include "base/string_util.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "chromeos/dbus/dbus_thread_manager.h"
12 #include "chromeos/dbus/experimental_bluetooth_adapter_client.h"
13 #include "chromeos/dbus/experimental_bluetooth_agent_manager_client.h"
14 #include "chromeos/dbus/experimental_bluetooth_agent_service_provider.h"
15 #include "chromeos/dbus/experimental_bluetooth_device_client.h"
16 #include "chromeos/dbus/experimental_bluetooth_input_client.h"
18 #include "device/bluetooth/bluetooth_adapter_experimental_chromeos.h"
19 #include "device/bluetooth/bluetooth_profile_experimental_chromeos.h"
20 #include "device/bluetooth/bluetooth_socket.h"
21 #include "third_party/cros_system_api/dbus/service_constants.h"
23 using device::BluetoothDevice
;
27 // The agent path is relatively meaningless since BlueZ only supports one
28 // at time and will fail in an attempt to register another with "Already Exists"
29 // (which we fail in OnRegisterAgentError with ERROR_INPROGRESS).
30 const char kAgentPath
[] = "/org/chromium/bluetooth_agent";
32 // Histogram enumerations for pairing methods.
33 enum UMAPairingMethod
{
34 UMA_PAIRING_METHOD_NONE
,
35 UMA_PAIRING_METHOD_REQUEST_PINCODE
,
36 UMA_PAIRING_METHOD_REQUEST_PASSKEY
,
37 UMA_PAIRING_METHOD_DISPLAY_PINCODE
,
38 UMA_PAIRING_METHOD_DISPLAY_PASSKEY
,
39 UMA_PAIRING_METHOD_CONFIRM_PASSKEY
,
40 // NOTE: Add new pairing methods immediately above this line. Make sure to
41 // update the enum list in tools/histogram/histograms.xml accordinly.
42 UMA_PAIRING_METHOD_COUNT
45 // Histogram enumerations for pairing results.
46 enum UMAPairingResult
{
47 UMA_PAIRING_RESULT_SUCCESS
,
48 UMA_PAIRING_RESULT_INPROGRESS
,
49 UMA_PAIRING_RESULT_FAILED
,
50 UMA_PAIRING_RESULT_AUTH_FAILED
,
51 UMA_PAIRING_RESULT_AUTH_CANCELED
,
52 UMA_PAIRING_RESULT_AUTH_REJECTED
,
53 UMA_PAIRING_RESULT_AUTH_TIMEOUT
,
54 UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE
,
55 UMA_PAIRING_RESULT_UNKNOWN_ERROR
,
56 // NOTE: Add new pairing results immediately above this line. Make sure to
57 // update the enum list in tools/histogram/histograms.xml accordinly.
58 UMA_PAIRING_RESULT_COUNT
61 void ParseModalias(const dbus::ObjectPath
& object_path
,
65 chromeos::ExperimentalBluetoothDeviceClient::Properties
* properties
=
66 chromeos::DBusThreadManager::Get()->
67 GetExperimentalBluetoothDeviceClient()->GetProperties(object_path
);
70 std::string modalias
= properties
->modalias
.value();
71 if (StartsWithASCII(modalias
, "usb:", false) && modalias
.length() == 19) {
72 // usb:vXXXXpXXXXdXXXX
73 if (modalias
[4] == 'v' && vendor_id
!= NULL
) {
75 base::HexStringToUInt64(modalias
.substr(5, 4), &component
);
76 *vendor_id
= component
;
79 if (modalias
[9] == 'p' && product_id
!= NULL
) {
81 base::HexStringToUInt64(modalias
.substr(10, 4), &component
);
82 *product_id
= component
;
85 if (modalias
[14] == 'd' && device_id
!= NULL
) {
87 base::HexStringToUInt64(modalias
.substr(15, 4), &component
);
88 *device_id
= component
;
93 void RecordPairingResult(BluetoothDevice::ConnectErrorCode error_code
) {
94 UMAPairingResult pairing_result
;
96 case BluetoothDevice::ERROR_INPROGRESS
:
97 pairing_result
= UMA_PAIRING_RESULT_INPROGRESS
;
99 case BluetoothDevice::ERROR_FAILED
:
100 pairing_result
= UMA_PAIRING_RESULT_FAILED
;
102 case BluetoothDevice::ERROR_AUTH_FAILED
:
103 pairing_result
= UMA_PAIRING_RESULT_AUTH_FAILED
;
105 case BluetoothDevice::ERROR_AUTH_CANCELED
:
106 pairing_result
= UMA_PAIRING_RESULT_AUTH_CANCELED
;
108 case BluetoothDevice::ERROR_AUTH_REJECTED
:
109 pairing_result
= UMA_PAIRING_RESULT_AUTH_REJECTED
;
111 case BluetoothDevice::ERROR_AUTH_TIMEOUT
:
112 pairing_result
= UMA_PAIRING_RESULT_AUTH_TIMEOUT
;
114 case BluetoothDevice::ERROR_UNSUPPORTED_DEVICE
:
115 pairing_result
= UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE
;
118 pairing_result
= UMA_PAIRING_RESULT_UNKNOWN_ERROR
;
121 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult",
123 UMA_PAIRING_RESULT_COUNT
);
130 BluetoothDeviceExperimentalChromeOS::BluetoothDeviceExperimentalChromeOS(
131 BluetoothAdapterExperimentalChromeOS
* adapter
,
132 const dbus::ObjectPath
& object_path
)
134 object_path_(object_path
),
135 num_connecting_calls_(0),
136 pairing_delegate_(NULL
),
137 pairing_delegate_used_(false),
138 weak_ptr_factory_(this) {
141 BluetoothDeviceExperimentalChromeOS::~BluetoothDeviceExperimentalChromeOS() {
144 uint32
BluetoothDeviceExperimentalChromeOS::GetBluetoothClass() const {
145 ExperimentalBluetoothDeviceClient::Properties
* properties
=
146 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
147 GetProperties(object_path_
);
150 return properties
->bluetooth_class
.value();
153 std::string
BluetoothDeviceExperimentalChromeOS::GetDeviceName() const {
154 ExperimentalBluetoothDeviceClient::Properties
* properties
=
155 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
156 GetProperties(object_path_
);
159 return properties
->alias
.value();
162 std::string
BluetoothDeviceExperimentalChromeOS::GetAddress() const {
163 ExperimentalBluetoothDeviceClient::Properties
* properties
=
164 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
165 GetProperties(object_path_
);
168 return properties
->address
.value();
171 uint16
BluetoothDeviceExperimentalChromeOS::GetVendorID() const {
172 uint16 vendor_id
= 0;
173 ParseModalias(object_path_
, &vendor_id
, NULL
, NULL
);
177 uint16
BluetoothDeviceExperimentalChromeOS::GetProductID() const {
178 uint16 product_id
= 0;
179 ParseModalias(object_path_
, NULL
, &product_id
, NULL
);
183 uint16
BluetoothDeviceExperimentalChromeOS::GetDeviceID() const {
184 uint16 device_id
= 0;
185 ParseModalias(object_path_
, NULL
, NULL
, &device_id
);
189 bool BluetoothDeviceExperimentalChromeOS::IsPaired() const {
190 ExperimentalBluetoothDeviceClient::Properties
* properties
=
191 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
192 GetProperties(object_path_
);
195 // Trusted devices are devices that don't support pairing but that the
196 // user has explicitly connected; it makes no sense for UI purposes to
197 // treat them differently from each other.
198 return properties
->paired
.value() || properties
->trusted
.value();
201 bool BluetoothDeviceExperimentalChromeOS::IsConnected() const {
202 ExperimentalBluetoothDeviceClient::Properties
* properties
=
203 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
204 GetProperties(object_path_
);
207 return properties
->connected
.value();
210 bool BluetoothDeviceExperimentalChromeOS::IsConnectable() const {
211 ExperimentalBluetoothInputClient::Properties
* input_properties
=
212 DBusThreadManager::Get()->GetExperimentalBluetoothInputClient()->
213 GetProperties(object_path_
);
214 // GetProperties returns NULL when the device does not implement the given
215 // interface. Non HID devices are normally connectable.
216 if (!input_properties
)
219 return input_properties
->reconnect_mode
.value() != "device";
222 bool BluetoothDeviceExperimentalChromeOS::IsConnecting() const {
223 return num_connecting_calls_
> 0;
226 BluetoothDeviceExperimentalChromeOS::ServiceList
227 BluetoothDeviceExperimentalChromeOS::GetServices() const {
228 ExperimentalBluetoothDeviceClient::Properties
* properties
=
229 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
230 GetProperties(object_path_
);
233 return properties
->uuids
.value();
236 void BluetoothDeviceExperimentalChromeOS::GetServiceRecords(
237 const ServiceRecordsCallback
& callback
,
238 const ErrorCallback
& error_callback
) {
239 // TODO(keybuk): not implemented; remove
240 error_callback
.Run();
243 void BluetoothDeviceExperimentalChromeOS::ProvidesServiceWithName(
244 const std::string
& name
,
245 const ProvidesServiceCallback
& callback
) {
246 // TODO(keybuk): not implemented; remove
250 bool BluetoothDeviceExperimentalChromeOS::ExpectingPinCode() const {
251 return !pincode_callback_
.is_null();
254 bool BluetoothDeviceExperimentalChromeOS::ExpectingPasskey() const {
255 return !passkey_callback_
.is_null();
258 bool BluetoothDeviceExperimentalChromeOS::ExpectingConfirmation() const {
259 return !confirmation_callback_
.is_null();
262 void BluetoothDeviceExperimentalChromeOS::Connect(
263 BluetoothDevice::PairingDelegate
* pairing_delegate
,
264 const base::Closure
& callback
,
265 const ConnectErrorCallback
& error_callback
) {
266 if (num_connecting_calls_
++ == 0)
267 adapter_
->NotifyDeviceChanged(this);
269 VLOG(1) << object_path_
.value() << ": Connecting, " << num_connecting_calls_
272 if (IsPaired() || !pairing_delegate
|| !IsPairable()) {
273 // No need to pair, or unable to, skip straight to connection.
274 ConnectInternal(false, callback
, error_callback
);
276 // Initiate high-security connection with pairing.
277 DCHECK(!pairing_delegate_
);
278 DCHECK(agent_
.get() == NULL
);
280 pairing_delegate_
= pairing_delegate
;
281 pairing_delegate_used_
= false;
283 // The agent path is relatively meaningless since BlueZ only supports
284 // one per application at a time.
285 dbus::Bus
* system_bus
= DBusThreadManager::Get()->GetSystemBus();
286 agent_
.reset(ExperimentalBluetoothAgentServiceProvider::Create(
287 system_bus
, dbus::ObjectPath(kAgentPath
), this));
288 DCHECK(agent_
.get());
290 VLOG(1) << object_path_
.value() << ": Registering agent for pairing";
291 DBusThreadManager::Get()->GetExperimentalBluetoothAgentManagerClient()->
293 dbus::ObjectPath(kAgentPath
),
294 bluetooth_agent_manager::kKeyboardDisplayCapability
,
296 &BluetoothDeviceExperimentalChromeOS::OnRegisterAgent
,
297 weak_ptr_factory_
.GetWeakPtr(),
301 &BluetoothDeviceExperimentalChromeOS::OnRegisterAgentError
,
302 weak_ptr_factory_
.GetWeakPtr(),
307 void BluetoothDeviceExperimentalChromeOS::SetPinCode(
308 const std::string
& pincode
) {
309 if (!agent_
.get() || pincode_callback_
.is_null())
312 pincode_callback_
.Run(SUCCESS
, pincode
);
313 pincode_callback_
.Reset();
316 void BluetoothDeviceExperimentalChromeOS::SetPasskey(uint32 passkey
) {
317 if (!agent_
.get() || passkey_callback_
.is_null())
320 passkey_callback_
.Run(SUCCESS
, passkey
);
321 passkey_callback_
.Reset();
324 void BluetoothDeviceExperimentalChromeOS::ConfirmPairing() {
325 if (!agent_
.get() || confirmation_callback_
.is_null())
328 confirmation_callback_
.Run(SUCCESS
);
329 confirmation_callback_
.Reset();
332 void BluetoothDeviceExperimentalChromeOS::RejectPairing() {
333 RunPairingCallbacks(REJECTED
);
336 void BluetoothDeviceExperimentalChromeOS::CancelPairing() {
337 // If there wasn't a callback in progress that we can reply to then we
338 // have to send a CancelPairing() to the device instead.
339 if (!RunPairingCallbacks(CANCELLED
)) {
340 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
343 base::Bind(&base::DoNothing
),
345 &BluetoothDeviceExperimentalChromeOS::OnCancelPairingError
,
346 weak_ptr_factory_
.GetWeakPtr()));
348 // Since there's no calback to this method, it's possible that the pairing
349 // delegate is going to be freed before things complete.
354 void BluetoothDeviceExperimentalChromeOS::Disconnect(
355 const base::Closure
& callback
,
356 const ErrorCallback
& error_callback
) {
357 VLOG(1) << object_path_
.value() << ": Disconnecting";
358 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
362 &BluetoothDeviceExperimentalChromeOS::OnDisconnect
,
363 weak_ptr_factory_
.GetWeakPtr(),
366 &BluetoothDeviceExperimentalChromeOS::OnDisconnectError
,
367 weak_ptr_factory_
.GetWeakPtr(),
371 void BluetoothDeviceExperimentalChromeOS::Forget(
372 const ErrorCallback
& error_callback
) {
373 VLOG(1) << object_path_
.value() << ": Removing device";
374 DBusThreadManager::Get()->GetExperimentalBluetoothAdapterClient()->
376 adapter_
->object_path_
,
378 base::Bind(&base::DoNothing
),
380 &BluetoothDeviceExperimentalChromeOS::OnForgetError
,
381 weak_ptr_factory_
.GetWeakPtr(),
385 void BluetoothDeviceExperimentalChromeOS::ConnectToService(
386 const std::string
& service_uuid
,
387 const SocketCallback
& callback
) {
388 // TODO(keybuk): implement
389 callback
.Run(scoped_refptr
<device::BluetoothSocket
>());
392 void BluetoothDeviceExperimentalChromeOS::ConnectToProfile(
393 device::BluetoothProfile
* profile
,
394 const base::Closure
& callback
,
395 const ErrorCallback
& error_callback
) {
396 BluetoothProfileExperimentalChromeOS
* profile_chromeos
=
397 static_cast<BluetoothProfileExperimentalChromeOS
*>(profile
);
398 VLOG(1) << object_path_
.value() << ": Connecting profile: "
399 << profile_chromeos
->uuid();
400 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
403 profile_chromeos
->uuid(),
405 &BluetoothDeviceExperimentalChromeOS::OnConnectProfile
,
406 weak_ptr_factory_
.GetWeakPtr(),
410 &BluetoothDeviceExperimentalChromeOS::OnConnectProfileError
,
411 weak_ptr_factory_
.GetWeakPtr(),
416 void BluetoothDeviceExperimentalChromeOS::SetOutOfBandPairingData(
417 const device::BluetoothOutOfBandPairingData
& data
,
418 const base::Closure
& callback
,
419 const ErrorCallback
& error_callback
) {
420 // TODO(keybuk): implement
421 error_callback
.Run();
424 void BluetoothDeviceExperimentalChromeOS::ClearOutOfBandPairingData(
425 const base::Closure
& callback
,
426 const ErrorCallback
& error_callback
) {
427 // TODO(keybuk): implement
428 error_callback
.Run();
432 void BluetoothDeviceExperimentalChromeOS::Release() {
433 DCHECK(agent_
.get());
434 DCHECK(pairing_delegate_
);
435 VLOG(1) << object_path_
.value() << ": Release";
437 pincode_callback_
.Reset();
438 passkey_callback_
.Reset();
439 confirmation_callback_
.Reset();
444 void BluetoothDeviceExperimentalChromeOS::RequestPinCode(
445 const dbus::ObjectPath
& device_path
,
446 const PinCodeCallback
& callback
) {
447 DCHECK(agent_
.get());
448 DCHECK(device_path
== object_path_
);
449 VLOG(1) << object_path_
.value() << ": RequestPinCode";
451 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
452 UMA_PAIRING_METHOD_REQUEST_PINCODE
,
453 UMA_PAIRING_METHOD_COUNT
);
455 DCHECK(pairing_delegate_
);
456 DCHECK(pincode_callback_
.is_null());
457 pincode_callback_
= callback
;
458 pairing_delegate_
->RequestPinCode(this);
459 pairing_delegate_used_
= true;
462 void BluetoothDeviceExperimentalChromeOS::DisplayPinCode(
463 const dbus::ObjectPath
& device_path
,
464 const std::string
& pincode
) {
465 DCHECK(agent_
.get());
466 DCHECK(device_path
== object_path_
);
467 VLOG(1) << object_path_
.value() << ": DisplayPinCode: " << pincode
;
469 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
470 UMA_PAIRING_METHOD_DISPLAY_PINCODE
,
471 UMA_PAIRING_METHOD_COUNT
);
473 DCHECK(pairing_delegate_
);
474 pairing_delegate_
->DisplayPinCode(this, pincode
);
475 pairing_delegate_used_
= true;
478 void BluetoothDeviceExperimentalChromeOS::RequestPasskey(
479 const dbus::ObjectPath
& device_path
,
480 const PasskeyCallback
& callback
) {
481 DCHECK(agent_
.get());
482 DCHECK(device_path
== object_path_
);
483 VLOG(1) << object_path_
.value() << ": RequestPasskey";
485 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
486 UMA_PAIRING_METHOD_REQUEST_PASSKEY
,
487 UMA_PAIRING_METHOD_COUNT
);
489 DCHECK(pairing_delegate_
);
490 DCHECK(passkey_callback_
.is_null());
491 passkey_callback_
= callback
;
492 pairing_delegate_
->RequestPasskey(this);
493 pairing_delegate_used_
= true;
496 void BluetoothDeviceExperimentalChromeOS::DisplayPasskey(
497 const dbus::ObjectPath
& device_path
,
500 DCHECK(agent_
.get());
501 DCHECK(device_path
== object_path_
);
502 VLOG(1) << object_path_
.value() << ": DisplayPasskey: " << passkey
503 << " (" << entered
<< " entered)";
506 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
507 UMA_PAIRING_METHOD_DISPLAY_PASSKEY
,
508 UMA_PAIRING_METHOD_COUNT
);
510 DCHECK(pairing_delegate_
);
512 pairing_delegate_
->DisplayPasskey(this, passkey
);
513 pairing_delegate_
->KeysEntered(this, entered
);
514 pairing_delegate_used_
= true;
517 void BluetoothDeviceExperimentalChromeOS::RequestConfirmation(
518 const dbus::ObjectPath
& device_path
,
520 const ConfirmationCallback
& callback
) {
521 DCHECK(agent_
.get());
522 DCHECK(device_path
== object_path_
);
523 VLOG(1) << object_path_
.value() << ": RequestConfirmation: " << passkey
;
525 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
526 UMA_PAIRING_METHOD_CONFIRM_PASSKEY
,
527 UMA_PAIRING_METHOD_COUNT
);
529 DCHECK(pairing_delegate_
);
530 DCHECK(confirmation_callback_
.is_null());
531 confirmation_callback_
= callback
;
532 pairing_delegate_
->ConfirmPasskey(this, passkey
);
533 pairing_delegate_used_
= true;
536 void BluetoothDeviceExperimentalChromeOS::RequestAuthorization(
537 const dbus::ObjectPath
& device_path
,
538 const ConfirmationCallback
& callback
) {
539 // TODO(keybuk): implement
540 callback
.Run(CANCELLED
);
543 void BluetoothDeviceExperimentalChromeOS::AuthorizeService(
544 const dbus::ObjectPath
& device_path
,
545 const std::string
& uuid
,
546 const ConfirmationCallback
& callback
) {
547 // TODO(keybuk): implement
548 callback
.Run(CANCELLED
);
551 void BluetoothDeviceExperimentalChromeOS::Cancel() {
552 DCHECK(agent_
.get());
553 VLOG(1) << object_path_
.value() << ": Cancel";
555 DCHECK(pairing_delegate_
);
556 pairing_delegate_
->DismissDisplayOrConfirm();
559 void BluetoothDeviceExperimentalChromeOS::ConnectInternal(
561 const base::Closure
& callback
,
562 const ConnectErrorCallback
& error_callback
) {
563 VLOG(1) << object_path_
.value() << ": Connecting";
564 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
568 &BluetoothDeviceExperimentalChromeOS::OnConnect
,
569 weak_ptr_factory_
.GetWeakPtr(),
573 &BluetoothDeviceExperimentalChromeOS::OnConnectError
,
574 weak_ptr_factory_
.GetWeakPtr(),
579 void BluetoothDeviceExperimentalChromeOS::OnConnect(
581 const base::Closure
& callback
) {
582 if (--num_connecting_calls_
== 0)
583 adapter_
->NotifyDeviceChanged(this);
585 DCHECK(num_connecting_calls_
>= 0);
586 VLOG(1) << object_path_
.value() << ": Connected, " << num_connecting_calls_
587 << " still in progress";
592 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult",
593 UMA_PAIRING_RESULT_SUCCESS
,
594 UMA_PAIRING_RESULT_COUNT
);
599 void BluetoothDeviceExperimentalChromeOS::OnConnectError(
601 const ConnectErrorCallback
& error_callback
,
602 const std::string
& error_name
,
603 const std::string
& error_message
) {
604 if (--num_connecting_calls_
== 0)
605 adapter_
->NotifyDeviceChanged(this);
607 DCHECK(num_connecting_calls_
>= 0);
608 LOG(WARNING
) << object_path_
.value() << ": Failed to connect device: "
609 << error_name
<< ": " << error_message
;
610 VLOG(1) << object_path_
.value() << ": " << num_connecting_calls_
611 << " still in progress";
613 // Determine the error code from error_name.
614 ConnectErrorCode error_code
= ERROR_UNKNOWN
;
615 if (error_name
== bluetooth_adapter::kErrorFailed
) {
616 error_code
= ERROR_FAILED
;
617 } else if (error_name
== bluetooth_adapter::kErrorInProgress
) {
618 error_code
= ERROR_INPROGRESS
;
619 } else if (error_name
== bluetooth_adapter::kErrorNotSupported
) {
620 error_code
= ERROR_UNSUPPORTED_DEVICE
;
624 RecordPairingResult(error_code
);
625 error_callback
.Run(error_code
);
628 void BluetoothDeviceExperimentalChromeOS::OnRegisterAgent(
629 const base::Closure
& callback
,
630 const ConnectErrorCallback
& error_callback
) {
631 VLOG(1) << object_path_
.value() << ": Agent registered, now pairing";
633 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
636 &BluetoothDeviceExperimentalChromeOS::OnPair
,
637 weak_ptr_factory_
.GetWeakPtr(),
638 callback
, error_callback
),
640 &BluetoothDeviceExperimentalChromeOS::OnPairError
,
641 weak_ptr_factory_
.GetWeakPtr(),
645 void BluetoothDeviceExperimentalChromeOS::OnRegisterAgentError(
646 const ConnectErrorCallback
& error_callback
,
647 const std::string
& error_name
,
648 const std::string
& error_message
) {
649 if (--num_connecting_calls_
== 0)
650 adapter_
->NotifyDeviceChanged(this);
652 DCHECK(num_connecting_calls_
>= 0);
653 LOG(WARNING
) << object_path_
.value() << ": Failed to register agent: "
654 << error_name
<< ": " << error_message
;
655 VLOG(1) << object_path_
.value() << ": " << num_connecting_calls_
656 << " still in progress";
660 // Determine the error code from error_name.
661 ConnectErrorCode error_code
= ERROR_UNKNOWN
;
662 if (error_name
== bluetooth_adapter::kErrorAlreadyExists
)
663 error_code
= ERROR_INPROGRESS
;
665 RecordPairingResult(error_code
);
666 error_callback
.Run(error_code
);
669 void BluetoothDeviceExperimentalChromeOS::OnPair(
670 const base::Closure
& callback
,
671 const ConnectErrorCallback
& error_callback
) {
672 VLOG(1) << object_path_
.value() << ": Paired";
674 if (!pairing_delegate_used_
)
675 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
676 UMA_PAIRING_METHOD_NONE
,
677 UMA_PAIRING_METHOD_COUNT
);
680 ConnectInternal(true, callback
, error_callback
);
683 void BluetoothDeviceExperimentalChromeOS::OnPairError(
684 const ConnectErrorCallback
& error_callback
,
685 const std::string
& error_name
,
686 const std::string
& error_message
) {
687 if (--num_connecting_calls_
== 0)
688 adapter_
->NotifyDeviceChanged(this);
690 DCHECK(num_connecting_calls_
>= 0);
691 LOG(WARNING
) << object_path_
.value() << ": Failed to pair device: "
692 << error_name
<< ": " << error_message
;
693 VLOG(1) << object_path_
.value() << ": " << num_connecting_calls_
694 << " still in progress";
698 // Determine the error code from error_name.
699 ConnectErrorCode error_code
= ERROR_UNKNOWN
;
700 if (error_name
== bluetooth_adapter::kErrorConnectionAttemptFailed
) {
701 error_code
= ERROR_FAILED
;
702 } else if (error_name
== bluetooth_adapter::kErrorFailed
) {
703 error_code
= ERROR_FAILED
;
704 } else if (error_name
== bluetooth_adapter::kErrorAuthenticationFailed
) {
705 error_code
= ERROR_AUTH_FAILED
;
706 } else if (error_name
== bluetooth_adapter::kErrorAuthenticationCanceled
) {
707 error_code
= ERROR_AUTH_CANCELED
;
708 } else if (error_name
== bluetooth_adapter::kErrorAuthenticationRejected
) {
709 error_code
= ERROR_AUTH_REJECTED
;
710 } else if (error_name
== bluetooth_adapter::kErrorAuthenticationTimeout
) {
711 error_code
= ERROR_AUTH_TIMEOUT
;
714 RecordPairingResult(error_code
);
715 error_callback
.Run(error_code
);
718 void BluetoothDeviceExperimentalChromeOS::OnCancelPairingError(
719 const std::string
& error_name
,
720 const std::string
& error_message
) {
721 LOG(WARNING
) << object_path_
.value() << ": Failed to cancel pairing: "
722 << error_name
<< ": " << error_message
;
725 void BluetoothDeviceExperimentalChromeOS::SetTrusted() {
726 // Unconditionally send the property change, rather than checking the value
727 // first; there's no harm in doing this and it solves any race conditions
728 // with the property becoming true or false and this call happening before
729 // we get the D-Bus signal about the earlier change.
730 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
731 GetProperties(object_path_
)->trusted
.Set(
734 &BluetoothDeviceExperimentalChromeOS::OnSetTrusted
,
735 weak_ptr_factory_
.GetWeakPtr()));
738 void BluetoothDeviceExperimentalChromeOS::OnSetTrusted(bool success
) {
739 LOG_IF(WARNING
, !success
) << object_path_
.value()
740 << ": Failed to set device as trusted";
743 void BluetoothDeviceExperimentalChromeOS::UnregisterAgent() {
747 DCHECK(pairing_delegate_
);
749 DCHECK(pincode_callback_
.is_null());
750 DCHECK(passkey_callback_
.is_null());
751 DCHECK(confirmation_callback_
.is_null());
753 pairing_delegate_
->DismissDisplayOrConfirm();
754 pairing_delegate_
= NULL
;
758 // Clean up after ourselves.
759 VLOG(1) << object_path_
.value() << ": Unregistering pairing agent";
760 DBusThreadManager::Get()->GetExperimentalBluetoothAgentManagerClient()->
762 dbus::ObjectPath(kAgentPath
),
763 base::Bind(&base::DoNothing
),
765 &BluetoothDeviceExperimentalChromeOS::OnUnregisterAgentError
,
766 weak_ptr_factory_
.GetWeakPtr()));
769 void BluetoothDeviceExperimentalChromeOS::OnUnregisterAgentError(
770 const std::string
& error_name
,
771 const std::string
& error_message
) {
772 LOG(WARNING
) << object_path_
.value() << ": Failed to unregister agent: "
773 << error_name
<< ": " << error_message
;
776 void BluetoothDeviceExperimentalChromeOS::OnDisconnect(
777 const base::Closure
& callback
) {
778 VLOG(1) << object_path_
.value() << ": Disconnected";
782 void BluetoothDeviceExperimentalChromeOS::OnDisconnectError(
783 const ErrorCallback
& error_callback
,
784 const std::string
& error_name
,
785 const std::string
& error_message
) {
786 LOG(WARNING
) << object_path_
.value() << ": Failed to disconnect device: "
787 << error_name
<< ": " << error_message
;
788 error_callback
.Run();
791 void BluetoothDeviceExperimentalChromeOS::OnForgetError(
792 const ErrorCallback
& error_callback
,
793 const std::string
& error_name
,
794 const std::string
& error_message
) {
795 LOG(WARNING
) << object_path_
.value() << ": Failed to remove device: "
796 << error_name
<< ": " << error_message
;
797 error_callback
.Run();
800 bool BluetoothDeviceExperimentalChromeOS::RunPairingCallbacks(Status status
) {
804 bool callback_run
= false;
805 if (!pincode_callback_
.is_null()) {
806 pincode_callback_
.Run(status
, "");
807 pincode_callback_
.Reset();
811 if (!passkey_callback_
.is_null()) {
812 passkey_callback_
.Run(status
, 0);
813 passkey_callback_
.Reset();
817 if (!confirmation_callback_
.is_null()) {
818 confirmation_callback_
.Run(status
);
819 confirmation_callback_
.Reset();
826 void BluetoothDeviceExperimentalChromeOS::OnConnectProfile(
827 device::BluetoothProfile
* profile
,
828 const base::Closure
& callback
) {
829 BluetoothProfileExperimentalChromeOS
* profile_chromeos
=
830 static_cast<BluetoothProfileExperimentalChromeOS
*>(profile
);
831 VLOG(1) << object_path_
.value() << ": Profile connected: "
832 << profile_chromeos
->uuid();
836 void BluetoothDeviceExperimentalChromeOS::OnConnectProfileError(
837 device::BluetoothProfile
* profile
,
838 const ErrorCallback
& error_callback
,
839 const std::string
& error_name
,
840 const std::string
& error_message
) {
841 BluetoothProfileExperimentalChromeOS
* profile_chromeos
=
842 static_cast<BluetoothProfileExperimentalChromeOS
*>(profile
);
843 VLOG(1) << object_path_
.value() << ": Profile connection failed: "
844 << profile_chromeos
->uuid() << ": "
845 << error_name
<< ": " << error_message
;
846 error_callback
.Run();
849 } // namespace chromeos