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.
5 #include "components/pairing/bluetooth_controller_pairing_controller.h"
8 #include "base/logging.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "components/pairing/bluetooth_pairing_constants.h"
13 #include "components/pairing/pairing_api.pb.h"
14 #include "device/bluetooth/bluetooth_adapter_factory.h"
15 #include "device/bluetooth/bluetooth_discovery_session.h"
16 #include "net/base/io_buffer.h"
19 const int kReceiveSize
= 16384;
22 namespace pairing_chromeos
{
24 BluetoothControllerPairingController::BluetoothControllerPairingController()
25 : current_stage_(STAGE_NONE
),
26 got_initial_status_(false),
27 proto_decoder_(new ProtoDecoder(this)),
31 BluetoothControllerPairingController::~BluetoothControllerPairingController() {
35 device::BluetoothDevice
* BluetoothControllerPairingController::GetController() {
36 DCHECK(!controller_device_id_
.empty());
37 device::BluetoothDevice
* device
= adapter_
->GetDevice(controller_device_id_
);
39 LOG(ERROR
) << "Lost connection to controller.";
40 ChangeStage(STAGE_ESTABLISHING_CONNECTION_ERROR
);
46 void BluetoothControllerPairingController::ChangeStage(Stage new_stage
) {
47 if (current_stage_
== new_stage
)
49 current_stage_
= new_stage
;
50 FOR_EACH_OBSERVER(ControllerPairingController::Observer
, observers_
,
51 PairingStageChanged(new_stage
));
54 void BluetoothControllerPairingController::Reset() {
55 got_initial_status_
= false;
56 controller_device_id_
.clear();
57 discovery_session_
.reset();
65 adapter_
->RemoveObserver(this);
70 void BluetoothControllerPairingController::DeviceFound(
71 device::BluetoothDevice
* device
) {
72 DCHECK_EQ(current_stage_
, STAGE_DEVICES_DISCOVERY
);
73 DCHECK(thread_checker_
.CalledOnValidThread());
74 if (StartsWith(device
->GetName(), base::ASCIIToUTF16(kDeviceNamePrefix
),
76 discovered_devices_
.insert(device
->GetAddress());
77 FOR_EACH_OBSERVER(ControllerPairingController::Observer
, observers_
,
78 DiscoveredDevicesListChanged());
82 void BluetoothControllerPairingController::DeviceLost(
83 device::BluetoothDevice
* device
) {
84 DCHECK_EQ(current_stage_
, STAGE_DEVICES_DISCOVERY
);
85 DCHECK(thread_checker_
.CalledOnValidThread());
86 std::set
<std::string
>::iterator ix
=
87 discovered_devices_
.find(device
->GetAddress());
88 if (ix
!= discovered_devices_
.end()) {
89 discovered_devices_
.erase(ix
);
90 FOR_EACH_OBSERVER(ControllerPairingController::Observer
, observers_
,
91 DiscoveredDevicesListChanged());
95 void BluetoothControllerPairingController::OnSetPowered() {
96 DCHECK(thread_checker_
.CalledOnValidThread());
97 adapter_
->StartDiscoverySession(
98 base::Bind(&BluetoothControllerPairingController::OnStartDiscoverySession
,
99 ptr_factory_
.GetWeakPtr()),
100 base::Bind(&BluetoothControllerPairingController::OnError
,
101 ptr_factory_
.GetWeakPtr()));
104 void BluetoothControllerPairingController::OnGetAdapter(
105 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
106 DCHECK(thread_checker_
.CalledOnValidThread());
109 adapter_
->AddObserver(this);
111 if (adapter_
->IsPowered()) {
114 adapter_
->SetPowered(
116 base::Bind(&BluetoothControllerPairingController::OnSetPowered
,
117 ptr_factory_
.GetWeakPtr()),
118 base::Bind(&BluetoothControllerPairingController::OnError
,
119 ptr_factory_
.GetWeakPtr()));
123 void BluetoothControllerPairingController::OnStartDiscoverySession(
124 scoped_ptr
<device::BluetoothDiscoverySession
> discovery_session
) {
125 DCHECK(thread_checker_
.CalledOnValidThread());
126 discovery_session_
= discovery_session
.Pass();
127 ChangeStage(STAGE_DEVICES_DISCOVERY
);
129 device::BluetoothAdapter::DeviceList device_list
= adapter_
->GetDevices();
130 for (device::BluetoothAdapter::DeviceList::iterator ix
= device_list
.begin();
131 ix
!= device_list
.end(); ++ix
) {
136 void BluetoothControllerPairingController::OnConnect() {
137 DCHECK(thread_checker_
.CalledOnValidThread());
138 device::BluetoothDevice
* device
= GetController();
140 device
->ConnectToService(
141 device::BluetoothUUID(kPairingServiceUUID
),
142 base::Bind(&BluetoothControllerPairingController::OnConnectToService
,
143 ptr_factory_
.GetWeakPtr()),
144 base::Bind(&BluetoothControllerPairingController::OnErrorWithMessage
,
145 ptr_factory_
.GetWeakPtr()));
149 void BluetoothControllerPairingController::OnConnectToService(
150 scoped_refptr
<device::BluetoothSocket
> socket
) {
151 DCHECK(thread_checker_
.CalledOnValidThread());
156 base::Bind(&BluetoothControllerPairingController::OnReceiveComplete
,
157 ptr_factory_
.GetWeakPtr()),
158 base::Bind(&BluetoothControllerPairingController::OnReceiveError
,
159 ptr_factory_
.GetWeakPtr()));
162 void BluetoothControllerPairingController::OnSendComplete(int bytes_sent
) {}
164 void BluetoothControllerPairingController::OnReceiveComplete(
165 int bytes
, scoped_refptr
<net::IOBuffer
> io_buffer
) {
166 DCHECK(thread_checker_
.CalledOnValidThread());
167 proto_decoder_
->DecodeIOBuffer(bytes
, io_buffer
);
171 base::Bind(&BluetoothControllerPairingController::OnReceiveComplete
,
172 ptr_factory_
.GetWeakPtr()),
173 base::Bind(&BluetoothControllerPairingController::OnReceiveError
,
174 ptr_factory_
.GetWeakPtr()));
177 void BluetoothControllerPairingController::OnError() {
178 // TODO(zork): Add a stage for initialization error. (http://crbug.com/405744)
179 LOG(ERROR
) << "Pairing initialization failed";
183 void BluetoothControllerPairingController::OnErrorWithMessage(
184 const std::string
& message
) {
185 // TODO(zork): Add a stage for initialization error. (http://crbug.com/405744)
186 LOG(ERROR
) << message
;
190 void BluetoothControllerPairingController::OnConnectError(
191 device::BluetoothDevice::ConnectErrorCode error_code
) {
192 DCHECK(thread_checker_
.CalledOnValidThread());
193 device::BluetoothDevice
* device
= GetController();
195 if (device
&& device
->IsPaired()) {
196 // The connection attempt is only used to start the pairing between the
197 // devices. If the connection fails, it's not a problem as long as pairing
203 void BluetoothControllerPairingController::OnReceiveError(
204 device::BluetoothSocket::ErrorReason reason
,
205 const std::string
& error_message
) {
206 LOG(ERROR
) << reason
<< ", " << error_message
;
210 void BluetoothControllerPairingController::AddObserver(
211 ControllerPairingController::Observer
* observer
) {
212 observers_
.AddObserver(observer
);
215 void BluetoothControllerPairingController::RemoveObserver(
216 ControllerPairingController::Observer
* observer
) {
217 observers_
.RemoveObserver(observer
);
220 ControllerPairingController::Stage
221 BluetoothControllerPairingController::GetCurrentStage() {
222 return current_stage_
;
225 void BluetoothControllerPairingController::StartPairing() {
226 DCHECK(thread_checker_
.CalledOnValidThread());
227 DCHECK(current_stage_
== STAGE_NONE
||
228 current_stage_
== STAGE_DEVICE_NOT_FOUND
||
229 current_stage_
== STAGE_ESTABLISHING_CONNECTION_ERROR
||
230 current_stage_
== STAGE_HOST_ENROLLMENT_ERROR
);
231 // TODO(zork): Add a stage for no bluetooth. (http://crbug.com/405744)
232 if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
233 ChangeStage(STAGE_DEVICE_NOT_FOUND
);
237 device::BluetoothAdapterFactory::GetAdapter(
238 base::Bind(&BluetoothControllerPairingController::OnGetAdapter
,
239 ptr_factory_
.GetWeakPtr()));
243 ControllerPairingController::DeviceIdList
244 BluetoothControllerPairingController::GetDiscoveredDevices() {
245 DCHECK_EQ(current_stage_
, STAGE_DEVICES_DISCOVERY
);
246 return DeviceIdList(discovered_devices_
.begin(), discovered_devices_
.end());
249 void BluetoothControllerPairingController::ChooseDeviceForPairing(
250 const std::string
& device_id
) {
251 DCHECK_EQ(current_stage_
, STAGE_DEVICES_DISCOVERY
);
252 DCHECK(discovered_devices_
.count(device_id
));
253 discovery_session_
.reset();
254 controller_device_id_
= device_id
;
256 device::BluetoothDevice
* device
= GetController();
259 ChangeStage(STAGE_ESTABLISHING_CONNECTION
);
260 if (device
->IsPaired()) {
265 base::Bind(&BluetoothControllerPairingController::OnConnect
,
266 ptr_factory_
.GetWeakPtr()),
267 base::Bind(&BluetoothControllerPairingController::OnConnectError
,
268 ptr_factory_
.GetWeakPtr()));
273 void BluetoothControllerPairingController::RepeatDiscovery() {
274 DCHECK(current_stage_
== STAGE_DEVICE_NOT_FOUND
||
275 current_stage_
== STAGE_ESTABLISHING_CONNECTION_ERROR
||
276 current_stage_
== STAGE_HOST_ENROLLMENT_ERROR
);
281 std::string
BluetoothControllerPairingController::GetConfirmationCode() {
282 DCHECK_EQ(current_stage_
, STAGE_WAITING_FOR_CODE_CONFIRMATION
);
283 DCHECK(!confirmation_code_
.empty());
284 return confirmation_code_
;
287 void BluetoothControllerPairingController::SetConfirmationCodeIsCorrect(
289 DCHECK_EQ(current_stage_
, STAGE_WAITING_FOR_CODE_CONFIRMATION
);
291 device::BluetoothDevice
* device
= GetController();
296 device
->ConfirmPairing();
297 // Once pairing is confirmed, the connection will either be successful, or
298 // fail. Either case is acceptable as long as the devices are paired.
300 device
->RejectPairing();
301 controller_device_id_
.clear();
306 void BluetoothControllerPairingController::SetHostConfiguration(
308 const std::string
& lang
,
309 const std::string
& timezone
,
311 const std::string
& keyboard_layout
) {
312 // TODO(zork): Get configuration from UI and send to Host.
313 // (http://crbug.com/405744)
316 void BluetoothControllerPairingController::OnAuthenticationDone(
317 const std::string
& domain
,
318 const std::string
& auth_token
) {
319 DCHECK_EQ(current_stage_
, STAGE_WAITING_FOR_CREDENTIALS
);
321 pairing_api::PairDevices pair_devices
;
322 pair_devices
.set_api_version(kPairingAPIVersion
);
323 pair_devices
.mutable_parameters()->set_admin_access_token(auth_token
);
326 scoped_refptr
<net::IOBuffer
> io_buffer(
327 ProtoDecoder::SendPairDevices(pair_devices
, &size
));
331 base::Bind(&BluetoothControllerPairingController::OnSendComplete
,
332 ptr_factory_
.GetWeakPtr()),
333 base::Bind(&BluetoothControllerPairingController::OnErrorWithMessage
,
334 ptr_factory_
.GetWeakPtr()));
335 ChangeStage(STAGE_HOST_ENROLLMENT_IN_PROGRESS
);
338 void BluetoothControllerPairingController::StartSession() {
339 DCHECK_EQ(current_stage_
, STAGE_PAIRING_DONE
);
340 ChangeStage(STAGE_FINISHED
);
343 // ProtoDecoder::Observer:
344 void BluetoothControllerPairingController::OnHostStatusMessage(
345 const pairing_api::HostStatus
& message
) {
346 if (got_initial_status_
) {
347 // TODO(zork): Check that the domain matches. (http://crbug.com/405761)
348 // TODO(zork): Handling updating stages (http://crbug.com/405754).
349 pairing_api::CompleteSetup complete_setup
;
350 complete_setup
.set_api_version(kPairingAPIVersion
);
351 // TODO(zork): Get AddAnother from UI (http://crbug.com/405757)
352 complete_setup
.mutable_parameters()->set_add_another(false);
355 scoped_refptr
<net::IOBuffer
> io_buffer(
356 ProtoDecoder::SendCompleteSetup(complete_setup
, &size
));
360 base::Bind(&BluetoothControllerPairingController::OnSendComplete
,
361 ptr_factory_
.GetWeakPtr()),
363 &BluetoothControllerPairingController::OnErrorWithMessage
,
364 ptr_factory_
.GetWeakPtr()));
365 ChangeStage(STAGE_PAIRING_DONE
);
367 got_initial_status_
= true;
369 // TODO(zork): Check domain. (http://crbug.com/405761)
370 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS
);
374 void BluetoothControllerPairingController::OnConfigureHostMessage(
375 const pairing_api::ConfigureHost
& message
) {
379 void BluetoothControllerPairingController::OnPairDevicesMessage(
380 const pairing_api::PairDevices
& message
) {
384 void BluetoothControllerPairingController::OnCompleteSetupMessage(
385 const pairing_api::CompleteSetup
& message
) {
389 void BluetoothControllerPairingController::OnErrorMessage(
390 const pairing_api::Error
& message
) {
391 LOG(ERROR
) << message
.parameters().code() << ", " <<
392 message
.parameters().description();
393 ChangeStage(STAGE_HOST_ENROLLMENT_ERROR
);
396 void BluetoothControllerPairingController::DeviceAdded(
397 device::BluetoothAdapter
* adapter
,
398 device::BluetoothDevice
* device
) {
399 DCHECK_EQ(adapter
, adapter_
.get());
403 void BluetoothControllerPairingController::DeviceRemoved(
404 device::BluetoothAdapter
* adapter
,
405 device::BluetoothDevice
* device
) {
406 DCHECK_EQ(adapter
, adapter_
.get());
410 void BluetoothControllerPairingController::RequestPinCode(
411 device::BluetoothDevice
* device
) {
412 // Disallow unknown device.
413 device
->RejectPairing();
416 void BluetoothControllerPairingController::RequestPasskey(
417 device::BluetoothDevice
* device
) {
418 // Disallow unknown device.
419 device
->RejectPairing();
422 void BluetoothControllerPairingController::DisplayPinCode(
423 device::BluetoothDevice
* device
,
424 const std::string
& pincode
) {
425 // Disallow unknown device.
426 device
->RejectPairing();
429 void BluetoothControllerPairingController::DisplayPasskey(
430 device::BluetoothDevice
* device
,
432 // Disallow unknown device.
433 device
->RejectPairing();
436 void BluetoothControllerPairingController::KeysEntered(
437 device::BluetoothDevice
* device
,
439 // Disallow unknown device.
440 device
->RejectPairing();
443 void BluetoothControllerPairingController::ConfirmPasskey(
444 device::BluetoothDevice
* device
,
446 confirmation_code_
= base::StringPrintf("%06d", passkey
);
447 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION
);
450 void BluetoothControllerPairingController::AuthorizePairing(
451 device::BluetoothDevice
* device
) {
452 // Disallow unknown device.
453 device
->RejectPairing();
456 } // namespace pairing_chromeos