• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
BluetoothPairingChromeOS(BluetoothDeviceChromeOS * device,BluetoothDevice::PairingDelegate * pairing_delegate)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 
~BluetoothPairingChromeOS()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 
RequestPinCode(const BluetoothAgentServiceProvider::Delegate::PinCodeCallback & callback)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 
ExpectingPinCode() const87 bool BluetoothPairingChromeOS::ExpectingPinCode() const {
88   return !pincode_callback_.is_null();
89 }
90 
SetPinCode(const std::string & pincode)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 
DisplayPinCode(const std::string & pincode)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 
RequestPasskey(const BluetoothAgentServiceProvider::Delegate::PasskeyCallback & callback)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 
ExpectingPasskey() const134 bool BluetoothPairingChromeOS::ExpectingPasskey() const {
135   return !passkey_callback_.is_null();
136 }
137 
SetPasskey(uint32 passkey)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 
DisplayPasskey(uint32 passkey)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 
KeysEntered(uint16 entered)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 
RequestConfirmation(uint32 passkey,const BluetoothAgentServiceProvider::Delegate::ConfirmationCallback & callback)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 
RequestAuthorization(const BluetoothAgentServiceProvider::Delegate::ConfirmationCallback & callback)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 
ExpectingConfirmation() const202 bool BluetoothPairingChromeOS::ExpectingConfirmation() const {
203   return !confirmation_callback_.is_null();
204 }
205 
ConfirmPairing()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 
RejectPairing()220 bool BluetoothPairingChromeOS::RejectPairing() {
221   return RunPairingCallbacks(
222       BluetoothAgentServiceProvider::Delegate::REJECTED);
223 }
224 
CancelPairing()225 bool BluetoothPairingChromeOS::CancelPairing() {
226   return RunPairingCallbacks(
227       BluetoothAgentServiceProvider::Delegate::CANCELLED);
228 }
229 
230 BluetoothDevice::PairingDelegate*
GetPairingDelegate() const231 BluetoothPairingChromeOS::GetPairingDelegate() const {
232   return pairing_delegate_;
233 }
234 
ResetCallbacks()235 void BluetoothPairingChromeOS::ResetCallbacks() {
236   pincode_callback_.Reset();
237   passkey_callback_.Reset();
238   confirmation_callback_.Reset();
239 }
240 
RunPairingCallbacks(BluetoothAgentServiceProvider::Delegate::Status status)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