17d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
57d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "device/bluetooth/bluetooth_device_chromeos.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <stdio.h>
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/bind.h"
10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/metrics/histogram.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "chromeos/dbus/bluetooth_adapter_client.h"
157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "chromeos/dbus/bluetooth_device_client.h"
16c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chromeos/dbus/bluetooth_gatt_service_client.h"
177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "chromeos/dbus/bluetooth_input_client.h"
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/dbus/dbus_thread_manager.h"
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "dbus/bus.h"
207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "device/bluetooth/bluetooth_adapter_chromeos.h"
216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "device/bluetooth/bluetooth_gatt_connection_chromeos.h"
22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "device/bluetooth/bluetooth_pairing_chromeos.h"
23c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h"
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "device/bluetooth/bluetooth_socket.h"
25010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "device/bluetooth/bluetooth_socket_chromeos.h"
26010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "device/bluetooth/bluetooth_socket_thread.h"
27010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "device/bluetooth/bluetooth_uuid.h"
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "third_party/cros_system_api/dbus/service_constants.h"
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using device::BluetoothDevice;
31010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)using device::BluetoothSocket;
32010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)using device::BluetoothUUID;
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Histogram enumerations for pairing results.
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)enum UMAPairingResult {
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_PAIRING_RESULT_SUCCESS,
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_PAIRING_RESULT_INPROGRESS,
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_PAIRING_RESULT_FAILED,
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_PAIRING_RESULT_AUTH_FAILED,
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_PAIRING_RESULT_AUTH_CANCELED,
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_PAIRING_RESULT_AUTH_REJECTED,
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_PAIRING_RESULT_AUTH_TIMEOUT,
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE,
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_PAIRING_RESULT_UNKNOWN_ERROR,
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // NOTE: Add new pairing results immediately above this line. Make sure to
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // update the enum list in tools/histogram/histograms.xml accordinly.
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_PAIRING_RESULT_COUNT
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ParseModalias(const dbus::ObjectPath& object_path,
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   BluetoothDevice::VendorIDSource* vendor_id_source,
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   uint16* vendor_id,
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   uint16* product_id,
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   uint16* device_id) {
577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  chromeos::BluetoothDeviceClient::Properties* properties =
587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      chromeos::DBusThreadManager::Get()->GetBluetoothDeviceClient()->
597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          GetProperties(object_path);
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(properties);
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string modalias = properties->modalias.value();
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BluetoothDevice::VendorIDSource source_value;
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int vendor_value, product_value, device_value;
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (sscanf(modalias.c_str(), "bluetooth:v%04xp%04xd%04x",
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)             &vendor_value, &product_value, &device_value) == 3) {
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    source_value = BluetoothDevice::VENDOR_ID_BLUETOOTH;
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else if (sscanf(modalias.c_str(), "usb:v%04xp%04xd%04x",
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    &vendor_value, &product_value, &device_value) == 3) {
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    source_value = BluetoothDevice::VENDOR_ID_USB;
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (vendor_id_source != NULL)
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    *vendor_id_source = source_value;
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (vendor_id != NULL)
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    *vendor_id = vendor_value;
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (product_id != NULL)
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    *product_id = product_value;
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (device_id != NULL)
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    *device_id = device_value;
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void RecordPairingResult(BluetoothDevice::ConnectErrorCode error_code) {
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMAPairingResult pairing_result;
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  switch (error_code) {
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case BluetoothDevice::ERROR_INPROGRESS:
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pairing_result = UMA_PAIRING_RESULT_INPROGRESS;
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case BluetoothDevice::ERROR_FAILED:
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pairing_result = UMA_PAIRING_RESULT_FAILED;
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case BluetoothDevice::ERROR_AUTH_FAILED:
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pairing_result = UMA_PAIRING_RESULT_AUTH_FAILED;
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case BluetoothDevice::ERROR_AUTH_CANCELED:
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pairing_result = UMA_PAIRING_RESULT_AUTH_CANCELED;
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case BluetoothDevice::ERROR_AUTH_REJECTED:
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pairing_result = UMA_PAIRING_RESULT_AUTH_REJECTED;
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case BluetoothDevice::ERROR_AUTH_TIMEOUT:
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pairing_result = UMA_PAIRING_RESULT_AUTH_TIMEOUT;
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case BluetoothDevice::ERROR_UNSUPPORTED_DEVICE:
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pairing_result = UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE;
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    default:
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pairing_result = UMA_PAIRING_RESULT_UNKNOWN_ERROR;
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult",
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            pairing_result,
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            UMA_PAIRING_RESULT_COUNT);
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace chromeos {
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)BluetoothDeviceChromeOS::BluetoothDeviceChromeOS(
1247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    BluetoothAdapterChromeOS* adapter,
125010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const dbus::ObjectPath& object_path,
126010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
127010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    scoped_refptr<device::BluetoothSocketThread> socket_thread)
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : adapter_(adapter),
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      object_path_(object_path),
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      num_connecting_calls_(0),
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      connection_monitor_started_(false),
132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      ui_task_runner_(ui_task_runner),
133010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      socket_thread_(socket_thread),
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_ptr_factory_(this) {
135c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DBusThreadManager::Get()->GetBluetoothGattServiceClient()->AddObserver(this);
136c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
137c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Add all known GATT services.
138c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const std::vector<dbus::ObjectPath> gatt_services =
139c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      DBusThreadManager::Get()->GetBluetoothGattServiceClient()->GetServices();
140c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  for (std::vector<dbus::ObjectPath>::const_iterator it = gatt_services.begin();
141c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       it != gatt_services.end(); ++it) {
142c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    GattServiceAdded(*it);
143c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)BluetoothDeviceChromeOS::~BluetoothDeviceChromeOS() {
147c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DBusThreadManager::Get()->GetBluetoothGattServiceClient()->
148c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      RemoveObserver(this);
149c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
150c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Copy the GATT services list here and clear the original so that when we
151c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // send GattServiceRemoved(), GetGattServices() returns no services.
152c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  GattServiceMap gatt_services = gatt_services_;
153c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  gatt_services_.clear();
154c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  for (GattServiceMap::iterator iter = gatt_services.begin();
155c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       iter != gatt_services.end(); ++iter) {
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    DCHECK(adapter_);
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    adapter_->NotifyGattServiceRemoved(
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        static_cast<BluetoothRemoteGattServiceChromeOS*>(iter->second));
159c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    delete iter->second;
160c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
161c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
162c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)uint32 BluetoothDeviceChromeOS::GetBluetoothClass() const {
1647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothDeviceClient::Properties* properties =
1657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothDeviceClient()->
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path_);
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(properties);
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return properties->bluetooth_class.value();
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)std::string BluetoothDeviceChromeOS::GetDeviceName() const {
1737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothDeviceClient::Properties* properties =
1747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothDeviceClient()->
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path_);
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(properties);
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return properties->alias.value();
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)std::string BluetoothDeviceChromeOS::GetAddress() const {
1827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothDeviceClient::Properties* properties =
1837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothDeviceClient()->
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path_);
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(properties);
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return CanonicalizeAddress(properties->address.value());
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BluetoothDevice::VendorIDSource
191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BluetoothDeviceChromeOS::GetVendorIDSource() const {
192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VendorIDSource vendor_id_source = VENDOR_ID_UNKNOWN;
193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ParseModalias(object_path_, &vendor_id_source, NULL, NULL, NULL);
194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return vendor_id_source;
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)uint16 BluetoothDeviceChromeOS::GetVendorID() const {
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uint16 vendor_id  = 0;
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ParseModalias(object_path_, NULL, &vendor_id, NULL, NULL);
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return vendor_id;
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)uint16 BluetoothDeviceChromeOS::GetProductID() const {
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uint16 product_id  = 0;
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ParseModalias(object_path_, NULL, NULL, &product_id, NULL);
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return product_id;
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)uint16 BluetoothDeviceChromeOS::GetDeviceID() const {
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uint16 device_id  = 0;
211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ParseModalias(object_path_, NULL, NULL, NULL, &device_id);
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return device_id;
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuint BluetoothDeviceChromeOS::GetRSSI() const {
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  BluetoothDeviceClient::Properties* properties =
217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothDeviceClient()->GetProperties(
218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          object_path_);
219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(properties);
220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!IsConnected()) {
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    NOTIMPLEMENTED();
223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return kUnknownPower;
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return connection_monitor_started_ ? properties->connection_rssi.value()
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                     : kUnknownPower;
2285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
2295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuint BluetoothDeviceChromeOS::GetCurrentHostTransmitPower() const {
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  BluetoothDeviceClient::Properties* properties =
232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothDeviceClient()->GetProperties(
233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          object_path_);
234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(properties);
235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return IsConnected() && connection_monitor_started_
237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)             ? properties->connection_tx_power.value()
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)             : kUnknownPower;
2395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
2405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuint BluetoothDeviceChromeOS::GetMaximumHostTransmitPower() const {
242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  BluetoothDeviceClient::Properties* properties =
243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothDeviceClient()->GetProperties(
244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          object_path_);
245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(properties);
246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return IsConnected() ? properties->connection_tx_power_max.value()
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                       : kUnknownPower;
2495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
2505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool BluetoothDeviceChromeOS::IsPaired() const {
2527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothDeviceClient::Properties* properties =
2537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothDeviceClient()->
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path_);
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(properties);
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Trusted devices are devices that don't support pairing but that the
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // user has explicitly connected; it makes no sense for UI purposes to
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // treat them differently from each other.
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return properties->paired.value() || properties->trusted.value();
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool BluetoothDeviceChromeOS::IsConnected() const {
2647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothDeviceClient::Properties* properties =
2657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothDeviceClient()->
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path_);
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(properties);
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return properties->connected.value();
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool BluetoothDeviceChromeOS::IsConnectable() const {
2737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothInputClient::Properties* input_properties =
2747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothInputClient()->
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path_);
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // GetProperties returns NULL when the device does not implement the given
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // interface. Non HID devices are normally connectable.
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!input_properties)
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return true;
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return input_properties->reconnect_mode.value() != "device";
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool BluetoothDeviceChromeOS::IsConnecting() const {
285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return num_connecting_calls_ > 0;
286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
28823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)BluetoothDeviceChromeOS::UUIDList BluetoothDeviceChromeOS::GetUUIDs() const {
2897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothDeviceClient::Properties* properties =
2907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothDeviceClient()->
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path_);
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(properties);
293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
294c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::vector<device::BluetoothUUID> uuids;
295c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const std::vector<std::string> &dbus_uuids = properties->uuids.value();
296c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  for (std::vector<std::string>::const_iterator iter = dbus_uuids.begin();
297c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       iter != dbus_uuids.end(); ++iter) {
298c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    device::BluetoothUUID uuid(*iter);
299c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    DCHECK(uuid.IsValid());
300c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    uuids.push_back(uuid);
301c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
302c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return uuids;
303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool BluetoothDeviceChromeOS::ExpectingPinCode() const {
306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return pairing_.get() && pairing_->ExpectingPinCode();
307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool BluetoothDeviceChromeOS::ExpectingPasskey() const {
310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return pairing_.get() && pairing_->ExpectingPasskey();
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool BluetoothDeviceChromeOS::ExpectingConfirmation() const {
314a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return pairing_.get() && pairing_->ExpectingConfirmation();
315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::Connect(
318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    BluetoothDevice::PairingDelegate* pairing_delegate,
319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::Closure& callback,
320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ConnectErrorCallback& error_callback) {
321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (num_connecting_calls_++ == 0)
322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    adapter_->NotifyDeviceChanged(this);
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  VLOG(1) << object_path_.value() << ": Connecting, " << num_connecting_calls_
325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          << " in progress";
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (IsPaired() || !pairing_delegate || !IsPairable()) {
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // No need to pair, or unable to, skip straight to connection.
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ConnectInternal(false, callback, error_callback);
330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Initiate high-security connection with pairing.
332a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    BeginPairing(pairing_delegate);
333a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
334a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DBusThreadManager::Get()->GetBluetoothDeviceClient()->
335a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        Pair(object_path_,
336a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)             base::Bind(&BluetoothDeviceChromeOS::OnPair,
337a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                        weak_ptr_factory_.GetWeakPtr(),
338a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                        callback, error_callback),
339a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)             base::Bind(&BluetoothDeviceChromeOS::OnPairError,
340a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                        weak_ptr_factory_.GetWeakPtr(),
341a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                        error_callback));
342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::SetPinCode(const std::string& pincode) {
346a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!pairing_.get())
347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
349a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pairing_->SetPinCode(pincode);
350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) {
353a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!pairing_.get())
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
356a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pairing_->SetPasskey(passkey);
357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::ConfirmPairing() {
360a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!pairing_.get())
361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
363a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pairing_->ConfirmPairing();
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::RejectPairing() {
367a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!pairing_.get())
368a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
369a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
370a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pairing_->RejectPairing();
371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::CancelPairing() {
374a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool canceled = false;
375a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
376a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If there is a callback in progress that we can reply to then use that
377a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // to cancel the current pairing request.
378a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (pairing_.get() && pairing_->CancelPairing())
379a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    canceled = true;
380a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
381a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If not we have to send an explicit CancelPairing() to the device instead.
382a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!canceled) {
383a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    VLOG(1) << object_path_.value() << ": No pairing context or callback. "
384a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            << "Sending explicit cancel";
3857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DBusThreadManager::Get()->GetBluetoothDeviceClient()->
386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        CancelPairing(
387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            object_path_,
388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            base::Bind(&base::DoNothing),
3897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            base::Bind(&BluetoothDeviceChromeOS::OnCancelPairingError,
3907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                       weak_ptr_factory_.GetWeakPtr()));
391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
392a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
393a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Since there is no callback to this method it's possible that the pairing
394a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // delegate is going to be freed before things complete (indeed it's
395a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // documented that this is the method you should call while freeing the
396a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // pairing delegate), so clear our the context holding on to it.
397a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EndPairing();
398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::Disconnect(const base::Closure& callback,
4017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                         const ErrorCallback& error_callback) {
402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  VLOG(1) << object_path_.value() << ": Disconnecting";
4037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothDeviceClient()->
404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      Disconnect(
405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          object_path_,
4067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          base::Bind(&BluetoothDeviceChromeOS::OnDisconnect,
4077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
4087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     callback),
4097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          base::Bind(&BluetoothDeviceChromeOS::OnDisconnectError,
4107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
4117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     error_callback));
412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::Forget(const ErrorCallback& error_callback) {
415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  VLOG(1) << object_path_.value() << ": Removing device";
4167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothAdapterClient()->
417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      RemoveDevice(
418cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          adapter_->object_path(),
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          object_path_,
420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          base::Bind(&base::DoNothing),
4217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          base::Bind(&BluetoothDeviceChromeOS::OnForgetError,
4227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
4237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     error_callback));
424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
426010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void BluetoothDeviceChromeOS::ConnectToService(
427010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const BluetoothUUID& uuid,
428010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const ConnectToServiceCallback& callback,
429010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const ConnectToServiceErrorCallback& error_callback) {
430cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  VLOG(1) << object_path_.value() << ": Connecting to service: "
431cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          << uuid.canonical_value();
432cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_refptr<BluetoothSocketChromeOS> socket =
433cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      BluetoothSocketChromeOS::CreateBluetoothSocket(
4345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          ui_task_runner_, socket_thread_);
43503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  socket->Connect(this, uuid, BluetoothSocketChromeOS::SECURITY_LEVEL_MEDIUM,
43603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                  base::Bind(callback, socket), error_callback);
43703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
43803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
43903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BluetoothDeviceChromeOS::ConnectToServiceInsecurely(
44003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const BluetoothUUID& uuid,
44103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const ConnectToServiceCallback& callback,
44203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const ConnectToServiceErrorCallback& error_callback) {
44303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  VLOG(1) << object_path_.value() << ": Connecting insecurely to service: "
44403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          << uuid.canonical_value();
44503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  scoped_refptr<BluetoothSocketChromeOS> socket =
44603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      BluetoothSocketChromeOS::CreateBluetoothSocket(
44703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          ui_task_runner_, socket_thread_);
44803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  socket->Connect(this, uuid, BluetoothSocketChromeOS::SECURITY_LEVEL_LOW,
44903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                  base::Bind(callback, socket), error_callback);
450cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
451cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
452f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void BluetoothDeviceChromeOS::CreateGattConnection(
453f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      const GattConnectionCallback& callback,
454f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      const ConnectErrorCallback& error_callback) {
4556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // TODO(armansito): Until there is a way to create a reference counted GATT
4566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // connection in bluetoothd, simply do a regular connect.
4576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  Connect(NULL,
4586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          base::Bind(&BluetoothDeviceChromeOS::OnCreateGattConnection,
4596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
4606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                     callback),
4616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          error_callback);
462f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
463f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
464cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothDeviceChromeOS::StartConnectionMonitor(
465c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::Closure& callback,
466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ErrorCallback& error_callback) {
467cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothDeviceClient()->StartConnectionMonitor(
468cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      object_path_,
469cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(&BluetoothDeviceChromeOS::OnStartConnectionMonitor,
470cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr(),
471cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 callback),
472cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(&BluetoothDeviceChromeOS::OnStartConnectionMonitorError,
473cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr(),
474cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 error_callback));
475c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
476c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
477a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BluetoothPairingChromeOS* BluetoothDeviceChromeOS::BeginPairing(
478a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    BluetoothDevice::PairingDelegate* pairing_delegate) {
479a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pairing_.reset(new BluetoothPairingChromeOS(this, pairing_delegate));
480a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return pairing_.get();
481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
483a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothDeviceChromeOS::EndPairing() {
484a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pairing_.reset();
485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
487a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BluetoothPairingChromeOS* BluetoothDeviceChromeOS::GetPairing() const {
488a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return pairing_.get();
489c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
490c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
491c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid BluetoothDeviceChromeOS::GattServiceAdded(
492c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const dbus::ObjectPath& object_path) {
493c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (GetGattService(object_path.value())) {
494c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    VLOG(1) << "Remote GATT service already exists: " << object_path.value();
495c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
496c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
497c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
498c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  BluetoothGattServiceClient::Properties* properties =
499c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      DBusThreadManager::Get()->GetBluetoothGattServiceClient()->
500c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          GetProperties(object_path);
501c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK(properties);
502c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (properties->device.value() != object_path_) {
503c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    VLOG(2) << "Remote GATT service does not belong to this device.";
504c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
505c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
506c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
507c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  VLOG(1) << "Adding new remote GATT service for device: " << GetAddress();
508c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
509c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  BluetoothRemoteGattServiceChromeOS* service =
510116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new BluetoothRemoteGattServiceChromeOS(adapter_, this, object_path);
511116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
512c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  gatt_services_[service->GetIdentifier()] = service;
513c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK(service->object_path() == object_path);
514c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK(service->GetUUID().IsValid());
515c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
5165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(adapter_);
5175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  adapter_->NotifyGattServiceAdded(service);
518c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
519c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
520c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid BluetoothDeviceChromeOS::GattServiceRemoved(
521c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const dbus::ObjectPath& object_path) {
522c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  GattServiceMap::iterator iter = gatt_services_.find(object_path.value());
523c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (iter == gatt_services_.end()) {
5245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    VLOG(3) << "Unknown GATT service removed: " << object_path.value();
525c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
526c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
527c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
528c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  VLOG(1) << "Removing remote GATT service from device: " << GetAddress();
529c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
530c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  BluetoothRemoteGattServiceChromeOS* service =
531c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      static_cast<BluetoothRemoteGattServiceChromeOS*>(iter->second);
532c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK(service->object_path() == object_path);
533c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  gatt_services_.erase(iter);
5345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(adapter_);
5365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  adapter_->NotifyGattServiceRemoved(service);
5375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
538c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  delete service;
539c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
540c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
5417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::ConnectInternal(
542c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool after_pairing,
543c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::Closure& callback,
544c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ConnectErrorCallback& error_callback) {
545c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  VLOG(1) << object_path_.value() << ": Connecting";
5467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothDeviceClient()->
547c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      Connect(
548c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          object_path_,
5497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          base::Bind(&BluetoothDeviceChromeOS::OnConnect,
5507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
5517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     after_pairing,
5527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     callback),
5537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          base::Bind(&BluetoothDeviceChromeOS::OnConnectError,
5547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
5557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     after_pairing,
5567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     error_callback));
5577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
5587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
5597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::OnConnect(bool after_pairing,
5607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                        const base::Closure& callback) {
561c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (--num_connecting_calls_ == 0)
562c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    adapter_->NotifyDeviceChanged(this);
563c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
564c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(num_connecting_calls_ >= 0);
565c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  VLOG(1) << object_path_.value() << ": Connected, " << num_connecting_calls_
566c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        << " still in progress";
567c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
568c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetTrusted();
569c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
570c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (after_pairing)
571c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult",
572c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              UMA_PAIRING_RESULT_SUCCESS,
573c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              UMA_PAIRING_RESULT_COUNT);
574c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  callback.Run();
576c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
577c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void BluetoothDeviceChromeOS::OnCreateGattConnection(
5796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const GattConnectionCallback& callback) {
5806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  scoped_ptr<device::BluetoothGattConnection> conn(
5816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      new BluetoothGattConnectionChromeOS(
5826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          adapter_, GetAddress(), object_path_));
5836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  callback.Run(conn.Pass());
5846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
5856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
5867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::OnConnectError(
587c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool after_pairing,
588c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ConnectErrorCallback& error_callback,
589c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& error_name,
590c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& error_message) {
591c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (--num_connecting_calls_ == 0)
592c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    adapter_->NotifyDeviceChanged(this);
593c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
594c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(num_connecting_calls_ >= 0);
595c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  LOG(WARNING) << object_path_.value() << ": Failed to connect device: "
596c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               << error_name << ": " << error_message;
597c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
598c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          << " still in progress";
599c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
600c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Determine the error code from error_name.
601c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ConnectErrorCode error_code = ERROR_UNKNOWN;
602868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (error_name == bluetooth_device::kErrorFailed) {
603c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    error_code = ERROR_FAILED;
604868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else if (error_name == bluetooth_device::kErrorInProgress) {
605c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    error_code = ERROR_INPROGRESS;
606868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else if (error_name == bluetooth_device::kErrorNotSupported) {
607c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    error_code = ERROR_UNSUPPORTED_DEVICE;
608c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
609c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
610c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (after_pairing)
611c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    RecordPairingResult(error_code);
612c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  error_callback.Run(error_code);
613c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
614c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::OnPair(
616c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::Closure& callback,
617c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ConnectErrorCallback& error_callback) {
618c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  VLOG(1) << object_path_.value() << ": Paired";
619c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
620a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EndPairing();
621a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
622c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ConnectInternal(true, callback, error_callback);
623c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
624c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::OnPairError(
626c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ConnectErrorCallback& error_callback,
627c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& error_name,
628c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& error_message) {
629c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (--num_connecting_calls_ == 0)
630c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    adapter_->NotifyDeviceChanged(this);
631c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
632c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(num_connecting_calls_ >= 0);
633c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  LOG(WARNING) << object_path_.value() << ": Failed to pair device: "
634c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               << error_name << ": " << error_message;
635c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
636c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          << " still in progress";
637c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
638a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EndPairing();
639c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
640c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Determine the error code from error_name.
641c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ConnectErrorCode error_code = ERROR_UNKNOWN;
642868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (error_name == bluetooth_device::kErrorConnectionAttemptFailed) {
643c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    error_code = ERROR_FAILED;
644868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else if (error_name == bluetooth_device::kErrorFailed) {
645b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    error_code = ERROR_FAILED;
646868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else if (error_name == bluetooth_device::kErrorAuthenticationFailed) {
647c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    error_code = ERROR_AUTH_FAILED;
648868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else if (error_name == bluetooth_device::kErrorAuthenticationCanceled) {
649c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    error_code = ERROR_AUTH_CANCELED;
650868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else if (error_name == bluetooth_device::kErrorAuthenticationRejected) {
651c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    error_code = ERROR_AUTH_REJECTED;
652868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else if (error_name == bluetooth_device::kErrorAuthenticationTimeout) {
653c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    error_code = ERROR_AUTH_TIMEOUT;
654c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
655c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
656c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RecordPairingResult(error_code);
657c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  error_callback.Run(error_code);
658c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
659c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::OnCancelPairingError(
661c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& error_name,
662c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& error_message) {
663c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  LOG(WARNING) << object_path_.value() << ": Failed to cancel pairing: "
664c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               << error_name << ": " << error_message;
665c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
666c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::SetTrusted() {
668c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Unconditionally send the property change, rather than checking the value
669c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // first; there's no harm in doing this and it solves any race conditions
670c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // with the property becoming true or false and this call happening before
671c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // we get the D-Bus signal about the earlier change.
6727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothDeviceClient()->
673c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      GetProperties(object_path_)->trusted.Set(
674c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          true,
6757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          base::Bind(&BluetoothDeviceChromeOS::OnSetTrusted,
6767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr()));
677c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
678c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::OnSetTrusted(bool success) {
680c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  LOG_IF(WARNING, !success) << object_path_.value()
681c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            << ": Failed to set device as trusted";
682c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
683c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
684cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothDeviceChromeOS::OnStartConnectionMonitor(
685cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::Closure& callback) {
686cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  connection_monitor_started_ = true;
687cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  callback.Run();
688cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
689cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
690cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothDeviceChromeOS::OnStartConnectionMonitorError(
691cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const ErrorCallback& error_callback,
692cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& error_name,
693cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& error_message) {
694cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  LOG(WARNING) << object_path_.value()
695cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)               << ": Failed to start connection monitor: " << error_name << ": "
696cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)               << error_message;
697cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  error_callback.Run();
698cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
699cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
7007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::OnDisconnect(const base::Closure& callback) {
701c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  VLOG(1) << object_path_.value() << ": Disconnected";
702c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  callback.Run();
703c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
704c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::OnDisconnectError(
706c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ErrorCallback& error_callback,
707c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& error_name,
708c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& error_message) {
709c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  LOG(WARNING) << object_path_.value() << ": Failed to disconnect device: "
710c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               << error_name << ": " << error_message;
711c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  error_callback.Run();
712c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
713c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothDeviceChromeOS::OnForgetError(
715c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ErrorCallback& error_callback,
716c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& error_name,
717c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& error_message) {
718c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  LOG(WARNING) << object_path_.value() << ": Failed to remove device: "
719c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               << error_name << ": " << error_message;
720c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  error_callback.Run();
721c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
722c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
723c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace chromeos
724