Home | History | Annotate | Download | only in bluetooth
      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 
     12 using device::BluetoothDevice;
     13 
     14 namespace {
     15 
     16 // Histogram enumerations for pairing methods.
     17 enum 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.
     31 const uint16 kPasskeyMaxKeysEntered = 7;
     32 
     33 }  // namespace
     34 
     35 namespace chromeos {
     36 
     37 BluetoothPairingChromeOS::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 
     47 BluetoothPairingChromeOS::~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 
     75 void 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 
     87 bool BluetoothPairingChromeOS::ExpectingPinCode() const {
     88   return !pincode_callback_.is_null();
     89 }
     90 
     91 void 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 
    106 void 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 
    122 void 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 
    134 bool BluetoothPairingChromeOS::ExpectingPasskey() const {
    135   return !passkey_callback_.is_null();
    136 }
    137 
    138 void 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 
    153 void 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 
    164 void 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 
    175 void 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 
    189 void 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 
    202 bool BluetoothPairingChromeOS::ExpectingConfirmation() const {
    203   return !confirmation_callback_.is_null();
    204 }
    205 
    206 void 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 
    220 bool BluetoothPairingChromeOS::RejectPairing() {
    221   return RunPairingCallbacks(
    222       BluetoothAgentServiceProvider::Delegate::REJECTED);
    223 }
    224 
    225 bool BluetoothPairingChromeOS::CancelPairing() {
    226   return RunPairingCallbacks(
    227       BluetoothAgentServiceProvider::Delegate::CANCELLED);
    228 }
    229 
    230 BluetoothDevice::PairingDelegate*
    231 BluetoothPairingChromeOS::GetPairingDelegate() const {
    232   return pairing_delegate_;
    233 }
    234 
    235 void BluetoothPairingChromeOS::ResetCallbacks() {
    236   pincode_callback_.Reset();
    237   passkey_callback_.Reset();
    238   confirmation_callback_.Reset();
    239 }
    240 
    241 bool 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