Include the proper animated gif for thread_times.key_idle_power_cases
[chromium-blink-merge.git] / components / pairing / bluetooth_host_pairing_controller.cc
blobc8246b1b10db0528906449b162013ee3d4eccc19
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_host_pairing_controller.h"
7 #include "base/bind.h"
8 #include "base/hash.h"
9 #include "base/logging.h"
10 #include "base/strings/stringprintf.h"
11 #include "components/pairing/bluetooth_pairing_constants.h"
12 #include "components/pairing/pairing_api.pb.h"
13 #include "components/pairing/proto_decoder.h"
14 #include "device/bluetooth/bluetooth_adapter_factory.h"
15 #include "net/base/io_buffer.h"
17 namespace pairing_chromeos {
19 namespace {
20 const int kReceiveSize = 16384;
22 pairing_api::HostStatusParameters::UpdateStatus PairingApiUpdateStatus(
23 HostPairingController::UpdateStatus update_status) {
24 switch(update_status) {
25 case HostPairingController::UPDATE_STATUS_UNKNOWN:
26 return pairing_api::HostStatusParameters::UPDATE_STATUS_UNKNOWN;
27 case HostPairingController::UPDATE_STATUS_UPDATING:
28 return pairing_api::HostStatusParameters::UPDATE_STATUS_UPDATING;
29 case HostPairingController::UPDATE_STATUS_REBOOTING:
30 return pairing_api::HostStatusParameters::UPDATE_STATUS_REBOOTING;
31 case HostPairingController::UPDATE_STATUS_UPDATED:
32 return pairing_api::HostStatusParameters::UPDATE_STATUS_UPDATED;
33 default:
34 NOTREACHED();
35 return pairing_api::HostStatusParameters::UPDATE_STATUS_UNKNOWN;
39 pairing_api::HostStatusParameters::EnrollmentStatus PairingApiEnrollmentStatus(
40 HostPairingController::EnrollmentStatus enrollment_status) {
41 switch(enrollment_status) {
42 case HostPairingController::ENROLLMENT_STATUS_UNKNOWN:
43 return pairing_api::HostStatusParameters::ENROLLMENT_STATUS_UNKNOWN;
44 case HostPairingController::ENROLLMENT_STATUS_ENROLLING:
45 return pairing_api::HostStatusParameters::ENROLLMENT_STATUS_ENROLLING;
46 case HostPairingController::ENROLLMENT_STATUS_FAILURE:
47 return pairing_api::HostStatusParameters::ENROLLMENT_STATUS_FAILURE;
48 case HostPairingController::ENROLLMENT_STATUS_SUCCESS:
49 return pairing_api::HostStatusParameters::ENROLLMENT_STATUS_SUCCESS;
50 default:
51 NOTREACHED();
52 return pairing_api::HostStatusParameters::ENROLLMENT_STATUS_UNKNOWN;
56 } // namespace
58 BluetoothHostPairingController::BluetoothHostPairingController()
59 : current_stage_(STAGE_NONE),
60 update_status_(UPDATE_STATUS_UNKNOWN),
61 enrollment_status_(ENROLLMENT_STATUS_UNKNOWN),
62 proto_decoder_(new ProtoDecoder(this)),
63 ptr_factory_(this) {
66 BluetoothHostPairingController::~BluetoothHostPairingController() {
67 if (adapter_.get()) {
68 if (adapter_->IsDiscoverable()) {
69 adapter_->SetDiscoverable(false, base::Closure(), base::Closure());
71 adapter_->RemoveObserver(this);
72 adapter_ = NULL;
76 void BluetoothHostPairingController::ChangeStage(Stage new_stage) {
77 if (current_stage_ == new_stage)
78 return;
79 VLOG(1) << "ChangeStage " << new_stage;
80 current_stage_ = new_stage;
81 FOR_EACH_OBSERVER(Observer, observers_, PairingStageChanged(new_stage));
84 void BluetoothHostPairingController::SendHostStatus() {
85 pairing_api::HostStatus host_status;
87 host_status.set_api_version(kPairingAPIVersion);
88 if (!enrollment_domain_.empty())
89 host_status.mutable_parameters()->set_domain(enrollment_domain_);
90 if (!permanent_id_.empty())
91 host_status.mutable_parameters()->set_permanent_id(permanent_id_);
93 // TODO(zork): Get these values from the UI. (http://crbug.com/405744)
94 host_status.mutable_parameters()->set_connectivity(
95 pairing_api::HostStatusParameters::CONNECTIVITY_CONNECTED);
96 host_status.mutable_parameters()->set_update_status(
97 PairingApiUpdateStatus(update_status_));
98 host_status.mutable_parameters()->set_enrollment_status(
99 PairingApiEnrollmentStatus(enrollment_status_));
101 // TODO(zork): Get a list of other paired controllers.
102 // (http://crbug.com/405757)
104 int size = 0;
105 scoped_refptr<net::IOBuffer> io_buffer(
106 ProtoDecoder::SendHostStatus(host_status, &size));
108 controller_socket_->Send(
109 io_buffer, size,
110 base::Bind(&BluetoothHostPairingController::OnSendComplete,
111 ptr_factory_.GetWeakPtr()),
112 base::Bind(&BluetoothHostPairingController::OnSendError,
113 ptr_factory_.GetWeakPtr()));
116 void BluetoothHostPairingController::AbortWithError(
117 int code,
118 const std::string& message) {
119 if (controller_socket_.get()) {
120 pairing_api::Error error;
122 error.set_api_version(kPairingAPIVersion);
123 error.mutable_parameters()->set_code(PAIRING_ERROR_PAIRING_OR_ENROLLMENT);
124 error.mutable_parameters()->set_description(message);
126 int size = 0;
127 scoped_refptr<net::IOBuffer> io_buffer(
128 ProtoDecoder::SendError(error, &size));
130 controller_socket_->Send(
131 io_buffer, size,
132 base::Bind(&BluetoothHostPairingController::OnSendComplete,
133 ptr_factory_.GetWeakPtr()),
134 base::Bind(&BluetoothHostPairingController::OnSendError,
135 ptr_factory_.GetWeakPtr()));
137 Reset();
140 void BluetoothHostPairingController::Reset() {
141 if (controller_socket_.get()) {
142 controller_socket_->Close();
143 controller_socket_ = NULL;
146 if (service_socket_.get()) {
147 service_socket_->Close();
148 service_socket_ = NULL;
150 ChangeStage(STAGE_NONE);
153 void BluetoothHostPairingController::OnGetAdapter(
154 scoped_refptr<device::BluetoothAdapter> adapter) {
155 DCHECK(thread_checker_.CalledOnValidThread());
156 DCHECK(!adapter_.get());
157 adapter_ = adapter;
159 if (adapter_->IsPresent()) {
160 SetName();
161 } else {
162 // Set the name once the adapter is present.
163 adapter_->AddObserver(this);
167 void BluetoothHostPairingController::SetName() {
168 // Hash the bluetooth address and take the lower 2 bytes to create a human
169 // readable device name.
170 const uint32 device_id = base::Hash(adapter_->GetAddress()) & 0xFFFF;
171 device_name_ = base::StringPrintf("%s%04X", kDeviceNamePrefix, device_id);
173 adapter_->SetName(
174 device_name_,
175 base::Bind(&BluetoothHostPairingController::OnSetName,
176 ptr_factory_.GetWeakPtr()),
177 base::Bind(&BluetoothHostPairingController::OnSetError,
178 ptr_factory_.GetWeakPtr()));
181 void BluetoothHostPairingController::OnSetName() {
182 DCHECK(thread_checker_.CalledOnValidThread());
183 if (adapter_->IsPowered()) {
184 OnSetPowered();
185 } else {
186 adapter_->SetPowered(
187 true,
188 base::Bind(&BluetoothHostPairingController::OnSetPowered,
189 ptr_factory_.GetWeakPtr()),
190 base::Bind(&BluetoothHostPairingController::OnSetError,
191 ptr_factory_.GetWeakPtr()));
195 void BluetoothHostPairingController::OnSetPowered() {
196 DCHECK(thread_checker_.CalledOnValidThread());
197 adapter_->AddPairingDelegate(
198 this, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
200 device::BluetoothAdapter::ServiceOptions options;
201 options.name.reset(new std::string(kPairingServiceName));
203 adapter_->CreateRfcommService(
204 device::BluetoothUUID(kPairingServiceUUID), options,
205 base::Bind(&BluetoothHostPairingController::OnCreateService,
206 ptr_factory_.GetWeakPtr()),
207 base::Bind(&BluetoothHostPairingController::OnCreateServiceError,
208 ptr_factory_.GetWeakPtr()));
211 void BluetoothHostPairingController::OnCreateService(
212 scoped_refptr<device::BluetoothSocket> socket) {
213 DCHECK(thread_checker_.CalledOnValidThread());
214 service_socket_ = socket;
216 service_socket_->Accept(
217 base::Bind(&BluetoothHostPairingController::OnAccept,
218 ptr_factory_.GetWeakPtr()),
219 base::Bind(&BluetoothHostPairingController::OnAcceptError,
220 ptr_factory_.GetWeakPtr()));
222 adapter_->SetDiscoverable(
223 true,
224 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable,
225 ptr_factory_.GetWeakPtr(), true),
226 base::Bind(&BluetoothHostPairingController::OnSetError,
227 ptr_factory_.GetWeakPtr()));
230 void BluetoothHostPairingController::OnAccept(
231 const device::BluetoothDevice* device,
232 scoped_refptr<device::BluetoothSocket> socket) {
233 DCHECK(thread_checker_.CalledOnValidThread());
234 adapter_->SetDiscoverable(
235 false,
236 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable,
237 ptr_factory_.GetWeakPtr(), false),
238 base::Bind(&BluetoothHostPairingController::OnSetError,
239 ptr_factory_.GetWeakPtr()));
241 controller_socket_ = socket;
242 service_socket_ = NULL;
244 SendHostStatus();
246 controller_socket_->Receive(
247 kReceiveSize,
248 base::Bind(&BluetoothHostPairingController::OnReceiveComplete,
249 ptr_factory_.GetWeakPtr()),
250 base::Bind(&BluetoothHostPairingController::OnReceiveError,
251 ptr_factory_.GetWeakPtr()));
254 void BluetoothHostPairingController::OnSetDiscoverable(bool change_stage) {
255 DCHECK(thread_checker_.CalledOnValidThread());
256 if (change_stage) {
257 DCHECK_EQ(current_stage_, STAGE_NONE);
258 ChangeStage(STAGE_WAITING_FOR_CONTROLLER);
262 void BluetoothHostPairingController::OnSendComplete(int bytes_sent) {}
264 void BluetoothHostPairingController::OnReceiveComplete(
265 int bytes, scoped_refptr<net::IOBuffer> io_buffer) {
266 DCHECK(thread_checker_.CalledOnValidThread());
267 proto_decoder_->DecodeIOBuffer(bytes, io_buffer);
269 controller_socket_->Receive(
270 kReceiveSize,
271 base::Bind(&BluetoothHostPairingController::OnReceiveComplete,
272 ptr_factory_.GetWeakPtr()),
273 base::Bind(&BluetoothHostPairingController::OnReceiveError,
274 ptr_factory_.GetWeakPtr()));
277 void BluetoothHostPairingController::OnCreateServiceError(
278 const std::string& message) {
279 LOG(ERROR) << message;
280 ChangeStage(STAGE_INITIALIZATION_ERROR);
283 void BluetoothHostPairingController::OnSetError() {
284 adapter_->RemovePairingDelegate(this);
285 ChangeStage(STAGE_INITIALIZATION_ERROR);
288 void BluetoothHostPairingController::OnAcceptError(
289 const std::string& error_message) {
290 LOG(ERROR) << error_message;
293 void BluetoothHostPairingController::OnSendError(
294 const std::string& error_message) {
295 LOG(ERROR) << error_message;
298 void BluetoothHostPairingController::OnReceiveError(
299 device::BluetoothSocket::ErrorReason reason,
300 const std::string& error_message) {
301 LOG(ERROR) << reason << ", " << error_message;
304 void BluetoothHostPairingController::OnHostStatusMessage(
305 const pairing_api::HostStatus& message) {
306 NOTREACHED();
309 void BluetoothHostPairingController::OnConfigureHostMessage(
310 const pairing_api::ConfigureHost& message) {
311 FOR_EACH_OBSERVER(Observer, observers_,
312 ConfigureHostRequested(
313 message.parameters().accepted_eula(),
314 message.parameters().lang(),
315 message.parameters().timezone(),
316 message.parameters().send_reports(),
317 message.parameters().keyboard_layout()));
320 void BluetoothHostPairingController::OnPairDevicesMessage(
321 const pairing_api::PairDevices& message) {
322 DCHECK(thread_checker_.CalledOnValidThread());
323 ChangeStage(STAGE_ENROLLING);
324 FOR_EACH_OBSERVER(Observer, observers_,
325 EnrollHostRequested(
326 message.parameters().admin_access_token()));
329 void BluetoothHostPairingController::OnCompleteSetupMessage(
330 const pairing_api::CompleteSetup& message) {
331 DCHECK(thread_checker_.CalledOnValidThread());
332 if (current_stage_ != STAGE_ENROLLMENT_SUCCESS) {
333 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorInvalidProtocol);
334 return;
337 // TODO(zork): Handle adding another controller. (http://crbug.com/405757)
338 ChangeStage(STAGE_FINISHED);
341 void BluetoothHostPairingController::OnErrorMessage(
342 const pairing_api::Error& message) {
343 NOTREACHED();
346 void BluetoothHostPairingController::OnAddNetworkMessage(
347 const pairing_api::AddNetwork& message) {
348 DCHECK(thread_checker_.CalledOnValidThread());
349 FOR_EACH_OBSERVER(Observer, observers_,
350 AddNetworkRequested(message.parameters().onc_spec()));
353 void BluetoothHostPairingController::AdapterPresentChanged(
354 device::BluetoothAdapter* adapter,
355 bool present) {
356 DCHECK_EQ(adapter, adapter_.get());
357 if (present) {
358 adapter_->RemoveObserver(this);
359 SetName();
363 void BluetoothHostPairingController::AddObserver(Observer* observer) {
364 observers_.AddObserver(observer);
367 void BluetoothHostPairingController::RemoveObserver(Observer* observer) {
368 observers_.RemoveObserver(observer);
371 HostPairingController::Stage BluetoothHostPairingController::GetCurrentStage() {
372 return current_stage_;
375 void BluetoothHostPairingController::StartPairing() {
376 DCHECK_EQ(current_stage_, STAGE_NONE);
377 bool bluetooth_available =
378 device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
379 if (!bluetooth_available) {
380 ChangeStage(STAGE_INITIALIZATION_ERROR);
381 return;
384 device::BluetoothAdapterFactory::GetAdapter(
385 base::Bind(&BluetoothHostPairingController::OnGetAdapter,
386 ptr_factory_.GetWeakPtr()));
389 std::string BluetoothHostPairingController::GetDeviceName() {
390 return device_name_;
393 std::string BluetoothHostPairingController::GetConfirmationCode() {
394 DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION);
395 return confirmation_code_;
398 std::string BluetoothHostPairingController::GetEnrollmentDomain() {
399 return enrollment_domain_;
402 void BluetoothHostPairingController::OnUpdateStatusChanged(
403 UpdateStatus update_status) {
404 update_status_ = update_status;
405 if (update_status == UPDATE_STATUS_UPDATED)
406 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS);
407 SendHostStatus();
410 void BluetoothHostPairingController::OnEnrollmentStatusChanged(
411 EnrollmentStatus enrollment_status) {
412 DCHECK_EQ(current_stage_, STAGE_ENROLLING);
413 DCHECK(thread_checker_.CalledOnValidThread());
415 enrollment_status_ = enrollment_status;
416 if (enrollment_status == ENROLLMENT_STATUS_SUCCESS) {
417 ChangeStage(STAGE_ENROLLMENT_SUCCESS);
418 } else if (enrollment_status == ENROLLMENT_STATUS_FAILURE) {
419 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT,
420 kErrorEnrollmentFailed);
422 SendHostStatus();
425 void BluetoothHostPairingController::SetPermanentId(
426 const std::string& permanent_id) {
427 permanent_id_ = permanent_id;
430 void BluetoothHostPairingController::RequestPinCode(
431 device::BluetoothDevice* device) {
432 // Disallow unknown device.
433 device->RejectPairing();
436 void BluetoothHostPairingController::RequestPasskey(
437 device::BluetoothDevice* device) {
438 // Disallow unknown device.
439 device->RejectPairing();
442 void BluetoothHostPairingController::DisplayPinCode(
443 device::BluetoothDevice* device,
444 const std::string& pincode) {
445 // Disallow unknown device.
446 device->RejectPairing();
449 void BluetoothHostPairingController::DisplayPasskey(
450 device::BluetoothDevice* device,
451 uint32 passkey) {
452 // Disallow unknown device.
453 device->RejectPairing();
456 void BluetoothHostPairingController::KeysEntered(
457 device::BluetoothDevice* device,
458 uint32 entered) {
459 // Disallow unknown device.
460 device->RejectPairing();
463 void BluetoothHostPairingController::ConfirmPasskey(
464 device::BluetoothDevice* device,
465 uint32 passkey) {
466 // If a new connection is occurring, reset the stage. This can occur if the
467 // pairing times out, or a new controller connects.
468 if (current_stage_ == STAGE_WAITING_FOR_CODE_CONFIRMATION)
469 ChangeStage(STAGE_WAITING_FOR_CONTROLLER);
471 confirmation_code_ = base::StringPrintf("%06d", passkey);
472 device->ConfirmPairing();
473 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION);
476 void BluetoothHostPairingController::AuthorizePairing(
477 device::BluetoothDevice* device) {
478 // Disallow unknown device.
479 device->RejectPairing();
482 } // namespace pairing_chromeos