[android_webview] Disable AwSettingsTest broken by Blink roll.
[chromium-blink-merge.git] / device / bluetooth / bluetooth_device_experimental_chromeos.cc
blobc7296baf60f9f9ef6116c5875799ee5e47f93493
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"
7 #include "base/bind.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"
17 #include "dbus/bus.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;
25 namespace {
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,
62 uint16 *vendor_id,
63 uint16 *product_id,
64 uint16 *device_id) {
65 chromeos::ExperimentalBluetoothDeviceClient::Properties* properties =
66 chromeos::DBusThreadManager::Get()->
67 GetExperimentalBluetoothDeviceClient()->GetProperties(object_path);
68 DCHECK(properties);
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) {
74 uint64 component = 0;
75 base::HexStringToUInt64(modalias.substr(5, 4), &component);
76 *vendor_id = component;
79 if (modalias[9] == 'p' && product_id != NULL) {
80 uint64 component = 0;
81 base::HexStringToUInt64(modalias.substr(10, 4), &component);
82 *product_id = component;
85 if (modalias[14] == 'd' && device_id != NULL) {
86 uint64 component = 0;
87 base::HexStringToUInt64(modalias.substr(15, 4), &component);
88 *device_id = component;
93 void RecordPairingResult(BluetoothDevice::ConnectErrorCode error_code) {
94 UMAPairingResult pairing_result;
95 switch (error_code) {
96 case BluetoothDevice::ERROR_INPROGRESS:
97 pairing_result = UMA_PAIRING_RESULT_INPROGRESS;
98 break;
99 case BluetoothDevice::ERROR_FAILED:
100 pairing_result = UMA_PAIRING_RESULT_FAILED;
101 break;
102 case BluetoothDevice::ERROR_AUTH_FAILED:
103 pairing_result = UMA_PAIRING_RESULT_AUTH_FAILED;
104 break;
105 case BluetoothDevice::ERROR_AUTH_CANCELED:
106 pairing_result = UMA_PAIRING_RESULT_AUTH_CANCELED;
107 break;
108 case BluetoothDevice::ERROR_AUTH_REJECTED:
109 pairing_result = UMA_PAIRING_RESULT_AUTH_REJECTED;
110 break;
111 case BluetoothDevice::ERROR_AUTH_TIMEOUT:
112 pairing_result = UMA_PAIRING_RESULT_AUTH_TIMEOUT;
113 break;
114 case BluetoothDevice::ERROR_UNSUPPORTED_DEVICE:
115 pairing_result = UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE;
116 break;
117 default:
118 pairing_result = UMA_PAIRING_RESULT_UNKNOWN_ERROR;
121 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult",
122 pairing_result,
123 UMA_PAIRING_RESULT_COUNT);
126 } // namespace
128 namespace chromeos {
130 BluetoothDeviceExperimentalChromeOS::BluetoothDeviceExperimentalChromeOS(
131 BluetoothAdapterExperimentalChromeOS* adapter,
132 const dbus::ObjectPath& object_path)
133 : adapter_(adapter),
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_);
148 DCHECK(properties);
150 return properties->bluetooth_class.value();
153 std::string BluetoothDeviceExperimentalChromeOS::GetDeviceName() const {
154 ExperimentalBluetoothDeviceClient::Properties* properties =
155 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
156 GetProperties(object_path_);
157 DCHECK(properties);
159 return properties->alias.value();
162 std::string BluetoothDeviceExperimentalChromeOS::GetAddress() const {
163 ExperimentalBluetoothDeviceClient::Properties* properties =
164 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
165 GetProperties(object_path_);
166 DCHECK(properties);
168 return properties->address.value();
171 uint16 BluetoothDeviceExperimentalChromeOS::GetVendorID() const {
172 uint16 vendor_id = 0;
173 ParseModalias(object_path_, &vendor_id, NULL, NULL);
174 return vendor_id;
177 uint16 BluetoothDeviceExperimentalChromeOS::GetProductID() const {
178 uint16 product_id = 0;
179 ParseModalias(object_path_, NULL, &product_id, NULL);
180 return product_id;
183 uint16 BluetoothDeviceExperimentalChromeOS::GetDeviceID() const {
184 uint16 device_id = 0;
185 ParseModalias(object_path_, NULL, NULL, &device_id);
186 return device_id;
189 bool BluetoothDeviceExperimentalChromeOS::IsPaired() const {
190 ExperimentalBluetoothDeviceClient::Properties* properties =
191 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
192 GetProperties(object_path_);
193 DCHECK(properties);
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_);
205 DCHECK(properties);
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)
217 return true;
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_);
231 DCHECK(properties);
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
247 callback.Run(false);
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_
270 << " in progress";
272 if (IsPaired() || !pairing_delegate || !IsPairable()) {
273 // No need to pair, or unable to, skip straight to connection.
274 ConnectInternal(false, callback, error_callback);
275 } else {
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()->
292 RegisterAgent(
293 dbus::ObjectPath(kAgentPath),
294 bluetooth_agent_manager::kKeyboardDisplayCapability,
295 base::Bind(
296 &BluetoothDeviceExperimentalChromeOS::OnRegisterAgent,
297 weak_ptr_factory_.GetWeakPtr(),
298 callback,
299 error_callback),
300 base::Bind(
301 &BluetoothDeviceExperimentalChromeOS::OnRegisterAgentError,
302 weak_ptr_factory_.GetWeakPtr(),
303 error_callback));
307 void BluetoothDeviceExperimentalChromeOS::SetPinCode(
308 const std::string& pincode) {
309 if (!agent_.get() || pincode_callback_.is_null())
310 return;
312 pincode_callback_.Run(SUCCESS, pincode);
313 pincode_callback_.Reset();
316 void BluetoothDeviceExperimentalChromeOS::SetPasskey(uint32 passkey) {
317 if (!agent_.get() || passkey_callback_.is_null())
318 return;
320 passkey_callback_.Run(SUCCESS, passkey);
321 passkey_callback_.Reset();
324 void BluetoothDeviceExperimentalChromeOS::ConfirmPairing() {
325 if (!agent_.get() || confirmation_callback_.is_null())
326 return;
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()->
341 CancelPairing(
342 object_path_,
343 base::Bind(&base::DoNothing),
344 base::Bind(
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.
350 UnregisterAgent();
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()->
359 Disconnect(
360 object_path_,
361 base::Bind(
362 &BluetoothDeviceExperimentalChromeOS::OnDisconnect,
363 weak_ptr_factory_.GetWeakPtr(),
364 callback),
365 base::Bind(
366 &BluetoothDeviceExperimentalChromeOS::OnDisconnectError,
367 weak_ptr_factory_.GetWeakPtr(),
368 error_callback));
371 void BluetoothDeviceExperimentalChromeOS::Forget(
372 const ErrorCallback& error_callback) {
373 VLOG(1) << object_path_.value() << ": Removing device";
374 DBusThreadManager::Get()->GetExperimentalBluetoothAdapterClient()->
375 RemoveDevice(
376 adapter_->object_path_,
377 object_path_,
378 base::Bind(&base::DoNothing),
379 base::Bind(
380 &BluetoothDeviceExperimentalChromeOS::OnForgetError,
381 weak_ptr_factory_.GetWeakPtr(),
382 error_callback));
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()->
401 ConnectProfile(
402 object_path_,
403 profile_chromeos->uuid(),
404 base::Bind(
405 &BluetoothDeviceExperimentalChromeOS::OnConnectProfile,
406 weak_ptr_factory_.GetWeakPtr(),
407 profile,
408 callback),
409 base::Bind(
410 &BluetoothDeviceExperimentalChromeOS::OnConnectProfileError,
411 weak_ptr_factory_.GetWeakPtr(),
412 profile,
413 error_callback));
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();
441 UnregisterAgent();
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,
498 uint32 passkey,
499 uint16 entered) {
500 DCHECK(agent_.get());
501 DCHECK(device_path == object_path_);
502 VLOG(1) << object_path_.value() << ": DisplayPasskey: " << passkey
503 << " (" << entered << " entered)";
505 if (entered == 0)
506 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
507 UMA_PAIRING_METHOD_DISPLAY_PASSKEY,
508 UMA_PAIRING_METHOD_COUNT);
510 DCHECK(pairing_delegate_);
511 if (entered == 0)
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,
519 uint32 passkey,
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(
560 bool after_pairing,
561 const base::Closure& callback,
562 const ConnectErrorCallback& error_callback) {
563 VLOG(1) << object_path_.value() << ": Connecting";
564 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
565 Connect(
566 object_path_,
567 base::Bind(
568 &BluetoothDeviceExperimentalChromeOS::OnConnect,
569 weak_ptr_factory_.GetWeakPtr(),
570 after_pairing,
571 callback),
572 base::Bind(
573 &BluetoothDeviceExperimentalChromeOS::OnConnectError,
574 weak_ptr_factory_.GetWeakPtr(),
575 after_pairing,
576 error_callback));
579 void BluetoothDeviceExperimentalChromeOS::OnConnect(
580 bool after_pairing,
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";
589 SetTrusted();
591 if (after_pairing)
592 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult",
593 UMA_PAIRING_RESULT_SUCCESS,
594 UMA_PAIRING_RESULT_COUNT);
596 callback.Run();
599 void BluetoothDeviceExperimentalChromeOS::OnConnectError(
600 bool after_pairing,
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;
623 if (after_pairing)
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()->
634 Pair(object_path_,
635 base::Bind(
636 &BluetoothDeviceExperimentalChromeOS::OnPair,
637 weak_ptr_factory_.GetWeakPtr(),
638 callback, error_callback),
639 base::Bind(
640 &BluetoothDeviceExperimentalChromeOS::OnPairError,
641 weak_ptr_factory_.GetWeakPtr(),
642 error_callback));
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";
658 UnregisterAgent();
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);
678 UnregisterAgent();
679 SetTrusted();
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";
696 UnregisterAgent();
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(
732 true,
733 base::Bind(
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() {
744 if (!agent_.get())
745 return;
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;
756 agent_.reset();
758 // Clean up after ourselves.
759 VLOG(1) << object_path_.value() << ": Unregistering pairing agent";
760 DBusThreadManager::Get()->GetExperimentalBluetoothAgentManagerClient()->
761 UnregisterAgent(
762 dbus::ObjectPath(kAgentPath),
763 base::Bind(&base::DoNothing),
764 base::Bind(
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";
779 callback.Run();
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) {
801 if (!agent_.get())
802 return false;
804 bool callback_run = false;
805 if (!pincode_callback_.is_null()) {
806 pincode_callback_.Run(status, "");
807 pincode_callback_.Reset();
808 callback_run = true;
811 if (!passkey_callback_.is_null()) {
812 passkey_callback_.Run(status, 0);
813 passkey_callback_.Reset();
814 callback_run = true;
817 if (!confirmation_callback_.is_null()) {
818 confirmation_callback_.Run(status);
819 confirmation_callback_.Reset();
820 callback_run = true;
823 return callback_run;
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();
833 callback.Run();
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