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