1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "device/bluetooth/bluetooth_pairing_chromeos.h" 6 7#include "base/logging.h" 8#include "base/metrics/histogram.h" 9#include "device/bluetooth/bluetooth_device.h" 10#include "device/bluetooth/bluetooth_device_chromeos.h" 11 12using device::BluetoothDevice; 13 14namespace { 15 16// Histogram enumerations for pairing methods. 17enum UMAPairingMethod { 18 UMA_PAIRING_METHOD_NONE, 19 UMA_PAIRING_METHOD_REQUEST_PINCODE, 20 UMA_PAIRING_METHOD_REQUEST_PASSKEY, 21 UMA_PAIRING_METHOD_DISPLAY_PINCODE, 22 UMA_PAIRING_METHOD_DISPLAY_PASSKEY, 23 UMA_PAIRING_METHOD_CONFIRM_PASSKEY, 24 // NOTE: Add new pairing methods immediately above this line. Make sure to 25 // update the enum list in tools/histogram/histograms.xml accordingly. 26 UMA_PAIRING_METHOD_COUNT 27}; 28 29// Number of keys that will be entered for a passkey, six digits plus the 30// final enter. 31const uint16 kPasskeyMaxKeysEntered = 7; 32 33} // namespace 34 35namespace chromeos { 36 37BluetoothPairingChromeOS::BluetoothPairingChromeOS( 38 BluetoothDeviceChromeOS* device, 39 BluetoothDevice::PairingDelegate* pairing_delegate) 40 : device_(device), 41 pairing_delegate_(pairing_delegate), 42 pairing_delegate_used_(false) { 43 VLOG(1) << "Created BluetoothPairingChromeOS for " 44 << device_->GetAddress(); 45} 46 47BluetoothPairingChromeOS::~BluetoothPairingChromeOS() { 48 VLOG(1) << "Destroying BluetoothPairingChromeOS for " 49 << device_->GetAddress(); 50 51 if (!pairing_delegate_used_) { 52 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", 53 UMA_PAIRING_METHOD_NONE, 54 UMA_PAIRING_METHOD_COUNT); 55 } 56 57 if (!pincode_callback_.is_null()) { 58 pincode_callback_.Run( 59 BluetoothAgentServiceProvider::Delegate::CANCELLED, ""); 60 } 61 62 if (!passkey_callback_.is_null()) { 63 passkey_callback_.Run( 64 BluetoothAgentServiceProvider::Delegate::CANCELLED, 0); 65 } 66 67 if (!confirmation_callback_.is_null()) { 68 confirmation_callback_.Run( 69 BluetoothAgentServiceProvider::Delegate::CANCELLED); 70 } 71 72 pairing_delegate_ = NULL; 73} 74 75void BluetoothPairingChromeOS::RequestPinCode( 76 const BluetoothAgentServiceProvider::Delegate::PinCodeCallback& callback) { 77 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", 78 UMA_PAIRING_METHOD_REQUEST_PINCODE, 79 UMA_PAIRING_METHOD_COUNT); 80 81 ResetCallbacks(); 82 pincode_callback_ = callback; 83 pairing_delegate_used_ = true; 84 pairing_delegate_->RequestPinCode(device_); 85} 86 87bool BluetoothPairingChromeOS::ExpectingPinCode() const { 88 return !pincode_callback_.is_null(); 89} 90 91void BluetoothPairingChromeOS::SetPinCode(const std::string& pincode) { 92 if (pincode_callback_.is_null()) 93 return; 94 95 pincode_callback_.Run(BluetoothAgentServiceProvider::Delegate::SUCCESS, 96 pincode); 97 pincode_callback_.Reset(); 98 99 // If this is not an outgoing connection to the device, clean up the pairing 100 // context since the pairing is done. The outgoing connection case is cleaned 101 // up in the callback for the underlying Pair() call. 102 if (!device_->IsConnecting()) 103 device_->EndPairing(); 104} 105 106void BluetoothPairingChromeOS::DisplayPinCode(const std::string& pincode) { 107 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", 108 UMA_PAIRING_METHOD_DISPLAY_PINCODE, 109 UMA_PAIRING_METHOD_COUNT); 110 111 ResetCallbacks(); 112 pairing_delegate_used_ = true; 113 pairing_delegate_->DisplayPinCode(device_, pincode); 114 115 // If this is not an outgoing connection to the device, the pairing context 116 // needs to be cleaned up again as there's no reliable indication of 117 // completion of incoming pairing. 118 if (!device_->IsConnecting()) 119 device_->EndPairing(); 120} 121 122void BluetoothPairingChromeOS::RequestPasskey( 123 const BluetoothAgentServiceProvider::Delegate::PasskeyCallback& callback) { 124 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", 125 UMA_PAIRING_METHOD_REQUEST_PASSKEY, 126 UMA_PAIRING_METHOD_COUNT); 127 128 ResetCallbacks(); 129 passkey_callback_ = callback; 130 pairing_delegate_used_ = true; 131 pairing_delegate_->RequestPasskey(device_); 132} 133 134bool BluetoothPairingChromeOS::ExpectingPasskey() const { 135 return !passkey_callback_.is_null(); 136} 137 138void BluetoothPairingChromeOS::SetPasskey(uint32 passkey) { 139 if (passkey_callback_.is_null()) 140 return; 141 142 passkey_callback_.Run(BluetoothAgentServiceProvider::Delegate::SUCCESS, 143 passkey); 144 passkey_callback_.Reset(); 145 146 // If this is not an outgoing connection to the device, clean up the pairing 147 // context since the pairing is done. The outgoing connection case is cleaned 148 // up in the callback for the underlying Pair() call. 149 if (!device_->IsConnecting()) 150 device_->EndPairing(); 151} 152 153void BluetoothPairingChromeOS::DisplayPasskey(uint32 passkey) { 154 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", 155 UMA_PAIRING_METHOD_DISPLAY_PASSKEY, 156 UMA_PAIRING_METHOD_COUNT); 157 158 ResetCallbacks(); 159 pairing_delegate_used_ = true; 160 pairing_delegate_->DisplayPasskey(device_, passkey); 161 162} 163 164void BluetoothPairingChromeOS::KeysEntered(uint16 entered) { 165 pairing_delegate_used_ = true; 166 pairing_delegate_->KeysEntered(device_, entered); 167 168 // If this is not an outgoing connection to the device, the pairing context 169 // needs to be cleaned up again as there's no reliable indication of 170 // completion of incoming pairing. 171 if (entered >= kPasskeyMaxKeysEntered && !device_->IsConnecting()) 172 device_->EndPairing(); 173} 174 175void BluetoothPairingChromeOS::RequestConfirmation( 176 uint32 passkey, 177 const BluetoothAgentServiceProvider::Delegate::ConfirmationCallback& 178 callback) { 179 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", 180 UMA_PAIRING_METHOD_CONFIRM_PASSKEY, 181 UMA_PAIRING_METHOD_COUNT); 182 183 ResetCallbacks(); 184 confirmation_callback_ = callback; 185 pairing_delegate_used_ = true; 186 pairing_delegate_->ConfirmPasskey(device_, passkey); 187} 188 189void BluetoothPairingChromeOS::RequestAuthorization( 190 const BluetoothAgentServiceProvider::Delegate::ConfirmationCallback& 191 callback) { 192 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", 193 UMA_PAIRING_METHOD_NONE, 194 UMA_PAIRING_METHOD_COUNT); 195 196 ResetCallbacks(); 197 confirmation_callback_ = callback; 198 pairing_delegate_used_ = true; 199 pairing_delegate_->AuthorizePairing(device_); 200} 201 202bool BluetoothPairingChromeOS::ExpectingConfirmation() const { 203 return !confirmation_callback_.is_null(); 204} 205 206void BluetoothPairingChromeOS::ConfirmPairing() { 207 if (confirmation_callback_.is_null()) 208 return; 209 210 confirmation_callback_.Run(BluetoothAgentServiceProvider::Delegate::SUCCESS); 211 confirmation_callback_.Reset(); 212 213 // If this is not an outgoing connection to the device, clean up the pairing 214 // context since the pairing is done. The outgoing connection case is cleaned 215 // up in the callback for the underlying Pair() call. 216 if (!device_->IsConnecting()) 217 device_->EndPairing(); 218} 219 220bool BluetoothPairingChromeOS::RejectPairing() { 221 return RunPairingCallbacks( 222 BluetoothAgentServiceProvider::Delegate::REJECTED); 223} 224 225bool BluetoothPairingChromeOS::CancelPairing() { 226 return RunPairingCallbacks( 227 BluetoothAgentServiceProvider::Delegate::CANCELLED); 228} 229 230BluetoothDevice::PairingDelegate* 231BluetoothPairingChromeOS::GetPairingDelegate() const { 232 return pairing_delegate_; 233} 234 235void BluetoothPairingChromeOS::ResetCallbacks() { 236 pincode_callback_.Reset(); 237 passkey_callback_.Reset(); 238 confirmation_callback_.Reset(); 239} 240 241bool BluetoothPairingChromeOS::RunPairingCallbacks( 242 BluetoothAgentServiceProvider::Delegate::Status status) { 243 pairing_delegate_used_ = true; 244 245 bool callback_run = false; 246 if (!pincode_callback_.is_null()) { 247 pincode_callback_.Run(status, ""); 248 pincode_callback_.Reset(); 249 callback_run = true; 250 } 251 252 if (!passkey_callback_.is_null()) { 253 passkey_callback_.Run(status, 0); 254 passkey_callback_.Reset(); 255 callback_run = true; 256 } 257 258 if (!confirmation_callback_.is_null()) { 259 confirmation_callback_.Run(status); 260 confirmation_callback_.Reset(); 261 callback_run = true; 262 } 263 264 // If this is not an outgoing connection to the device, clean up the pairing 265 // context since the pairing is done. The outgoing connection case is cleaned 266 // up in the callback for the underlying Pair() call. 267 if (!device_->IsConnecting()) 268 device_->EndPairing(); 269 270 return callback_run; 271} 272 273} // namespace chromeos 274