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 proto_decoder_(new ProtoDecoder(this)),
30 BluetoothControllerPairingController::~BluetoothControllerPairingController() {
34 device::BluetoothDevice
* BluetoothControllerPairingController::GetController() {
35 DCHECK(!controller_device_id_
.empty());
36 device::BluetoothDevice
* device
= adapter_
->GetDevice(controller_device_id_
);
38 LOG(ERROR
) << "Lost connection to controller.";
39 ChangeStage(STAGE_ESTABLISHING_CONNECTION_ERROR
);
45 void BluetoothControllerPairingController::ChangeStage(Stage new_stage
) {
46 if (current_stage_
== new_stage
)
48 VLOG(1) << "ChangeStage " << new_stage
;
49 current_stage_
= new_stage
;
50 FOR_EACH_OBSERVER(ControllerPairingController::Observer
, observers_
,
51 PairingStageChanged(new_stage
));
54 void BluetoothControllerPairingController::Reset() {
55 controller_device_id_
.clear();
56 discovery_session_
.reset();
64 adapter_
->RemoveObserver(this);
69 void BluetoothControllerPairingController::DeviceFound(
70 device::BluetoothDevice
* device
) {
71 DCHECK_EQ(current_stage_
, STAGE_DEVICES_DISCOVERY
);
72 DCHECK(thread_checker_
.CalledOnValidThread());
73 if (StartsWith(device
->GetName(), base::ASCIIToUTF16(kDeviceNamePrefix
),
75 discovered_devices_
.insert(device
->GetAddress());
76 FOR_EACH_OBSERVER(ControllerPairingController::Observer
, observers_
,
77 DiscoveredDevicesListChanged());
81 void BluetoothControllerPairingController::DeviceLost(
82 device::BluetoothDevice
* device
) {
83 DCHECK_EQ(current_stage_
, STAGE_DEVICES_DISCOVERY
);
84 DCHECK(thread_checker_
.CalledOnValidThread());
85 std::set
<std::string
>::iterator ix
=
86 discovered_devices_
.find(device
->GetAddress());
87 if (ix
!= discovered_devices_
.end()) {
88 discovered_devices_
.erase(ix
);
89 FOR_EACH_OBSERVER(ControllerPairingController::Observer
, observers_
,
90 DiscoveredDevicesListChanged());
94 void BluetoothControllerPairingController::SendBuffer(
95 scoped_refptr
<net::IOBuffer
> io_buffer
, int size
) {
98 base::Bind(&BluetoothControllerPairingController::OnSendComplete
,
99 ptr_factory_
.GetWeakPtr()),
100 base::Bind(&BluetoothControllerPairingController::OnErrorWithMessage
,
101 ptr_factory_
.GetWeakPtr()));
104 void BluetoothControllerPairingController::OnSetPowered() {
105 DCHECK(thread_checker_
.CalledOnValidThread());
106 adapter_
->StartDiscoverySession(
107 base::Bind(&BluetoothControllerPairingController::OnStartDiscoverySession
,
108 ptr_factory_
.GetWeakPtr()),
109 base::Bind(&BluetoothControllerPairingController::OnError
,
110 ptr_factory_
.GetWeakPtr()));
113 void BluetoothControllerPairingController::OnGetAdapter(
114 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
115 DCHECK(thread_checker_
.CalledOnValidThread());
116 DCHECK(!adapter_
.get());
118 adapter_
->AddObserver(this);
120 if (adapter_
->IsPowered()) {
123 adapter_
->SetPowered(
125 base::Bind(&BluetoothControllerPairingController::OnSetPowered
,
126 ptr_factory_
.GetWeakPtr()),
127 base::Bind(&BluetoothControllerPairingController::OnError
,
128 ptr_factory_
.GetWeakPtr()));
132 void BluetoothControllerPairingController::OnStartDiscoverySession(
133 scoped_ptr
<device::BluetoothDiscoverySession
> discovery_session
) {
134 DCHECK(thread_checker_
.CalledOnValidThread());
135 discovery_session_
= discovery_session
.Pass();
136 ChangeStage(STAGE_DEVICES_DISCOVERY
);
138 for (const auto& device
: adapter_
->GetDevices())
142 void BluetoothControllerPairingController::OnConnect() {
143 DCHECK(thread_checker_
.CalledOnValidThread());
144 device::BluetoothDevice
* device
= GetController();
146 device
->ConnectToService(
147 device::BluetoothUUID(kPairingServiceUUID
),
148 base::Bind(&BluetoothControllerPairingController::OnConnectToService
,
149 ptr_factory_
.GetWeakPtr()),
150 base::Bind(&BluetoothControllerPairingController::OnErrorWithMessage
,
151 ptr_factory_
.GetWeakPtr()));
155 void BluetoothControllerPairingController::OnConnectToService(
156 scoped_refptr
<device::BluetoothSocket
> socket
) {
157 DCHECK(thread_checker_
.CalledOnValidThread());
162 base::Bind(&BluetoothControllerPairingController::OnReceiveComplete
,
163 ptr_factory_
.GetWeakPtr()),
164 base::Bind(&BluetoothControllerPairingController::OnReceiveError
,
165 ptr_factory_
.GetWeakPtr()));
166 ChangeStage(STAGE_PAIRING_DONE
);
169 void BluetoothControllerPairingController::OnSendComplete(int bytes_sent
) {}
171 void BluetoothControllerPairingController::OnReceiveComplete(
172 int bytes
, scoped_refptr
<net::IOBuffer
> io_buffer
) {
173 DCHECK(thread_checker_
.CalledOnValidThread());
174 proto_decoder_
->DecodeIOBuffer(bytes
, io_buffer
);
178 base::Bind(&BluetoothControllerPairingController::OnReceiveComplete
,
179 ptr_factory_
.GetWeakPtr()),
180 base::Bind(&BluetoothControllerPairingController::OnReceiveError
,
181 ptr_factory_
.GetWeakPtr()));
184 void BluetoothControllerPairingController::OnError() {
185 LOG(ERROR
) << "Pairing initialization failed";
186 ChangeStage(STAGE_INITIALIZATION_ERROR
);
190 void BluetoothControllerPairingController::OnErrorWithMessage(
191 const std::string
& message
) {
192 LOG(ERROR
) << message
;
193 ChangeStage(STAGE_INITIALIZATION_ERROR
);
197 void BluetoothControllerPairingController::OnConnectError(
198 device::BluetoothDevice::ConnectErrorCode error_code
) {
199 DCHECK(thread_checker_
.CalledOnValidThread());
200 device::BluetoothDevice
* device
= GetController();
202 if (device
&& device
->IsPaired()) {
203 // The connection attempt is only used to start the pairing between the
204 // devices. If the connection fails, it's not a problem as long as pairing
208 // This can happen if the confirmation dialog times out.
209 ChangeStage(STAGE_ESTABLISHING_CONNECTION_ERROR
);
213 void BluetoothControllerPairingController::OnReceiveError(
214 device::BluetoothSocket::ErrorReason reason
,
215 const std::string
& error_message
) {
216 LOG(ERROR
) << reason
<< ", " << error_message
;
220 void BluetoothControllerPairingController::AddObserver(
221 ControllerPairingController::Observer
* observer
) {
222 observers_
.AddObserver(observer
);
225 void BluetoothControllerPairingController::RemoveObserver(
226 ControllerPairingController::Observer
* observer
) {
227 observers_
.RemoveObserver(observer
);
230 ControllerPairingController::Stage
231 BluetoothControllerPairingController::GetCurrentStage() {
232 return current_stage_
;
235 void BluetoothControllerPairingController::StartPairing() {
236 DCHECK(thread_checker_
.CalledOnValidThread());
237 DCHECK(current_stage_
== STAGE_NONE
||
238 current_stage_
== STAGE_DEVICE_NOT_FOUND
||
239 current_stage_
== STAGE_ESTABLISHING_CONNECTION_ERROR
||
240 current_stage_
== STAGE_HOST_ENROLLMENT_ERROR
);
241 if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
242 ChangeStage(STAGE_INITIALIZATION_ERROR
);
246 device::BluetoothAdapterFactory::GetAdapter(
247 base::Bind(&BluetoothControllerPairingController::OnGetAdapter
,
248 ptr_factory_
.GetWeakPtr()));
252 ControllerPairingController::DeviceIdList
253 BluetoothControllerPairingController::GetDiscoveredDevices() {
254 DCHECK_EQ(current_stage_
, STAGE_DEVICES_DISCOVERY
);
255 return DeviceIdList(discovered_devices_
.begin(), discovered_devices_
.end());
258 void BluetoothControllerPairingController::ChooseDeviceForPairing(
259 const std::string
& device_id
) {
260 DCHECK_EQ(current_stage_
, STAGE_DEVICES_DISCOVERY
);
261 DCHECK(discovered_devices_
.count(device_id
));
262 discovery_session_
.reset();
263 controller_device_id_
= device_id
;
265 device::BluetoothDevice
* device
= GetController();
268 ChangeStage(STAGE_ESTABLISHING_CONNECTION
);
269 if (device
->IsPaired()) {
274 base::Bind(&BluetoothControllerPairingController::OnConnect
,
275 ptr_factory_
.GetWeakPtr()),
276 base::Bind(&BluetoothControllerPairingController::OnConnectError
,
277 ptr_factory_
.GetWeakPtr()));
282 void BluetoothControllerPairingController::RepeatDiscovery() {
283 DCHECK(current_stage_
== STAGE_DEVICE_NOT_FOUND
||
284 current_stage_
== STAGE_ESTABLISHING_CONNECTION_ERROR
||
285 current_stage_
== STAGE_HOST_ENROLLMENT_ERROR
);
290 std::string
BluetoothControllerPairingController::GetConfirmationCode() {
291 DCHECK_EQ(current_stage_
, STAGE_WAITING_FOR_CODE_CONFIRMATION
);
292 DCHECK(!confirmation_code_
.empty());
293 return confirmation_code_
;
296 void BluetoothControllerPairingController::SetConfirmationCodeIsCorrect(
298 DCHECK_EQ(current_stage_
, STAGE_WAITING_FOR_CODE_CONFIRMATION
);
300 device::BluetoothDevice
* device
= GetController();
305 device
->ConfirmPairing();
306 // Once pairing is confirmed, the connection will either be successful, or
307 // fail. Either case is acceptable as long as the devices are paired.
309 device
->RejectPairing();
310 controller_device_id_
.clear();
315 void BluetoothControllerPairingController::SetHostConfiguration(
317 const std::string
& lang
,
318 const std::string
& timezone
,
320 const std::string
& keyboard_layout
) {
321 VLOG(1) << "SetHostConfiguration lang=" << lang
322 << ", timezone=" << timezone
323 << ", keyboard_layout=" << keyboard_layout
;
325 pairing_api::ConfigureHost host_config
;
326 host_config
.set_api_version(kPairingAPIVersion
);
327 host_config
.mutable_parameters()->set_accepted_eula(accepted_eula
);
328 host_config
.mutable_parameters()->set_lang(lang
);
329 host_config
.mutable_parameters()->set_timezone(timezone
);
330 host_config
.mutable_parameters()->set_send_reports(send_reports
);
331 host_config
.mutable_parameters()->set_keyboard_layout(keyboard_layout
);
334 scoped_refptr
<net::IOBuffer
> io_buffer(
335 ProtoDecoder::SendConfigureHost(host_config
, &size
));
337 SendBuffer(io_buffer
, size
);
340 void BluetoothControllerPairingController::OnAuthenticationDone(
341 const std::string
& domain
,
342 const std::string
& auth_token
) {
343 DCHECK_EQ(current_stage_
, STAGE_WAITING_FOR_CREDENTIALS
);
345 pairing_api::PairDevices pair_devices
;
346 pair_devices
.set_api_version(kPairingAPIVersion
);
347 pair_devices
.mutable_parameters()->set_admin_access_token(auth_token
);
350 scoped_refptr
<net::IOBuffer
> io_buffer(
351 ProtoDecoder::SendPairDevices(pair_devices
, &size
));
353 SendBuffer(io_buffer
, size
);
354 ChangeStage(STAGE_HOST_ENROLLMENT_IN_PROGRESS
);
357 void BluetoothControllerPairingController::StartSession() {
358 DCHECK_EQ(current_stage_
, STAGE_HOST_ENROLLMENT_SUCCESS
);
359 ChangeStage(STAGE_FINISHED
);
362 void BluetoothControllerPairingController::OnHostStatusMessage(
363 const pairing_api::HostStatus
& message
) {
364 pairing_api::HostStatusParameters::UpdateStatus update_status
=
365 message
.parameters().update_status();
366 pairing_api::HostStatusParameters::EnrollmentStatus enrollment_status
=
367 message
.parameters().enrollment_status();
368 VLOG(1) << "OnHostStatusMessage, update_status=" << update_status
;
369 // TODO(zork): Check domain. (http://crbug.com/405761)
370 if (enrollment_status
==
371 pairing_api::HostStatusParameters::ENROLLMENT_STATUS_SUCCESS
) {
372 // TODO(achuith, zork): Need to ensure that controller has also successfully
375 } else if (update_status
==
376 pairing_api::HostStatusParameters::UPDATE_STATUS_UPDATING
) {
377 ChangeStage(STAGE_HOST_UPDATE_IN_PROGRESS
);
378 } else if (update_status
==
379 pairing_api::HostStatusParameters::UPDATE_STATUS_UPDATED
) {
380 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS
);
384 void BluetoothControllerPairingController::CompleteSetup() {
385 pairing_api::CompleteSetup complete_setup
;
386 complete_setup
.set_api_version(kPairingAPIVersion
);
387 // TODO(zork): Get AddAnother from UI (http://crbug.com/405757)
388 complete_setup
.mutable_parameters()->set_add_another(false);
391 scoped_refptr
<net::IOBuffer
> io_buffer(
392 ProtoDecoder::SendCompleteSetup(complete_setup
, &size
));
394 SendBuffer(io_buffer
, size
);
395 ChangeStage(STAGE_HOST_ENROLLMENT_SUCCESS
);
398 void BluetoothControllerPairingController::OnConfigureHostMessage(
399 const pairing_api::ConfigureHost
& message
) {
403 void BluetoothControllerPairingController::OnPairDevicesMessage(
404 const pairing_api::PairDevices
& message
) {
408 void BluetoothControllerPairingController::OnCompleteSetupMessage(
409 const pairing_api::CompleteSetup
& message
) {
413 void BluetoothControllerPairingController::OnErrorMessage(
414 const pairing_api::Error
& message
) {
415 LOG(ERROR
) << message
.parameters().code() << ", " <<
416 message
.parameters().description();
417 ChangeStage(STAGE_HOST_ENROLLMENT_ERROR
);
420 void BluetoothControllerPairingController::DeviceAdded(
421 device::BluetoothAdapter
* adapter
,
422 device::BluetoothDevice
* device
) {
423 DCHECK_EQ(adapter
, adapter_
.get());
427 void BluetoothControllerPairingController::DeviceRemoved(
428 device::BluetoothAdapter
* adapter
,
429 device::BluetoothDevice
* device
) {
430 DCHECK_EQ(adapter
, adapter_
.get());
434 void BluetoothControllerPairingController::RequestPinCode(
435 device::BluetoothDevice
* device
) {
436 // Disallow unknown device.
437 device
->RejectPairing();
440 void BluetoothControllerPairingController::RequestPasskey(
441 device::BluetoothDevice
* device
) {
442 // Disallow unknown device.
443 device
->RejectPairing();
446 void BluetoothControllerPairingController::DisplayPinCode(
447 device::BluetoothDevice
* device
,
448 const std::string
& pincode
) {
449 // Disallow unknown device.
450 device
->RejectPairing();
453 void BluetoothControllerPairingController::DisplayPasskey(
454 device::BluetoothDevice
* device
,
456 // Disallow unknown device.
457 device
->RejectPairing();
460 void BluetoothControllerPairingController::KeysEntered(
461 device::BluetoothDevice
* device
,
463 // Disallow unknown device.
464 device
->RejectPairing();
467 void BluetoothControllerPairingController::ConfirmPasskey(
468 device::BluetoothDevice
* device
,
470 confirmation_code_
= base::StringPrintf("%06d", passkey
);
471 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION
);
474 void BluetoothControllerPairingController::AuthorizePairing(
475 device::BluetoothDevice
* device
) {
476 // Disallow unknown device.
477 device
->RejectPairing();
480 } // namespace pairing_chromeos