Index: components/pairing/bluetooth_controller_pairing_controller.cc |
diff --git a/components/pairing/bluetooth_controller_pairing_controller.cc b/components/pairing/bluetooth_controller_pairing_controller.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..12245ef4845b546cfaa2cdcd0156e18acaba1f16 |
--- /dev/null |
+++ b/components/pairing/bluetooth_controller_pairing_controller.cc |
@@ -0,0 +1,431 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "components/pairing/bluetooth_controller_pairing_controller.h" |
+ |
+#include "base/bind.h" |
+#include "base/logging.h" |
+#include "base/strings/string_util.h" |
+#include "base/strings/stringprintf.h" |
+#include "base/strings/utf_string_conversions.h" |
+#include "components/pairing/bluetooth_pairing_constants.h" |
+#include "components/pairing/pairing_api.pb.h" |
+#include "device/bluetooth/bluetooth_adapter_factory.h" |
+#include "device/bluetooth/bluetooth_discovery_session.h" |
+#include "net/base/io_buffer.h" |
+ |
+namespace { |
+const char* kFakeEnrollmentDomain = "http://fake.com"; |
+const int kReceiveSize = 16384; |
+} |
+ |
+namespace pairing_chromeos { |
+ |
+BluetoothControllerPairingController::BluetoothControllerPairingController() |
+ : ptr_factory_(this), |
+ current_stage_(STAGE_NONE), |
+ got_initial_status_(false), |
+ device_(NULL), |
+ proto_decoder_(new ProtoDecoder(this)) { |
+} |
achuithb
2014/08/20 21:52:32
Is this expected to be created and used on the UI
Zachary Kuznia
2014/08/21 00:42:07
Done.
|
+ |
+BluetoothControllerPairingController::~BluetoothControllerPairingController() { |
+ Reset(); |
+} |
+ |
+void BluetoothControllerPairingController::ChangeStage(Stage new_stage) { |
+ if (current_stage_ == new_stage) |
+ return; |
+ current_stage_ = new_stage; |
+ FOR_EACH_OBSERVER(ControllerPairingController::Observer, observers_, |
+ PairingStageChanged(new_stage)); |
+} |
+ |
+void BluetoothControllerPairingController::Reset() { |
+ got_initial_status_ = false; |
+ device_ = NULL; |
+ discovery_session_.reset(); |
+ |
+ if (socket_) { |
+ socket_->Close(); |
+ socket_ = NULL; |
+ } |
+ |
+ if (adapter_) { |
+ adapter_->RemoveObserver(this); |
+ adapter_ = NULL; |
+ } |
+} |
+ |
+void BluetoothControllerPairingController::DeviceFound( |
+ device::BluetoothDevice* device) { |
+ DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY); |
+ if (StartsWith(device->GetName(), base::ASCIIToUTF16(kDeviceNamePrefix), |
+ false)) { |
+ discovered_devices_.insert(device->GetAddress()); |
+ FOR_EACH_OBSERVER(ControllerPairingController::Observer, observers_, |
+ DiscoveredDevicesListChanged()); |
+ } |
+} |
+ |
+void BluetoothControllerPairingController::DeviceLost( |
+ device::BluetoothDevice* device) { |
+ DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY); |
+ std::set<std::string>::iterator ix = |
+ discovered_devices_.find(device->GetAddress()); |
+ if (ix != discovered_devices_.end()) { |
+ discovered_devices_.erase(ix); |
+ FOR_EACH_OBSERVER(ControllerPairingController::Observer, observers_, |
+ DiscoveredDevicesListChanged()); |
+ } |
+} |
+ |
+void BluetoothControllerPairingController::OnSetPowered() { |
+ adapter_->StartDiscoverySession( |
+ base::Bind(&BluetoothControllerPairingController::OnStartDiscoverySession, |
+ ptr_factory_.GetWeakPtr()), |
+ base::Bind(&BluetoothControllerPairingController::OnError, |
+ ptr_factory_.GetWeakPtr())); |
+} |
+ |
+void BluetoothControllerPairingController::OnGetAdapter( |
+ scoped_refptr<device::BluetoothAdapter> adapter) { |
+ CHECK(!adapter_); |
+ adapter_ = adapter; |
+ adapter_->AddObserver(this); |
+ |
+ if (adapter_->IsPowered()) { |
+ OnSetPowered(); |
+ } else { |
+ adapter_->SetPowered( |
+ true, |
+ base::Bind(&BluetoothControllerPairingController::OnSetPowered, |
+ ptr_factory_.GetWeakPtr()), |
+ base::Bind(&BluetoothControllerPairingController::OnError, |
+ ptr_factory_.GetWeakPtr())); |
+ } |
+} |
+ |
+void BluetoothControllerPairingController::OnStartDiscoverySession( |
+ scoped_ptr<device::BluetoothDiscoverySession> discovery_session) { |
+ discovery_session_ = discovery_session.Pass(); |
+ ChangeStage(STAGE_DEVICES_DISCOVERY); |
+ |
+ device::BluetoothAdapter::DeviceList device_list = adapter_->GetDevices(); |
+ for (device::BluetoothAdapter::DeviceList::iterator ix = device_list.begin(); |
+ ix != device_list.end(); ++ix) { |
+ DeviceFound(*ix); |
+ } |
+} |
+ |
+void BluetoothControllerPairingController::OnConnect() { |
+ device_->ConnectToService( |
+ device::BluetoothUUID(kPairingServiceUUID), |
+ base::Bind(&BluetoothControllerPairingController::OnConnectToService, |
+ ptr_factory_.GetWeakPtr()), |
+ base::Bind(&BluetoothControllerPairingController::OnErrorWithMessage, |
+ ptr_factory_.GetWeakPtr())); |
+} |
+ |
+void BluetoothControllerPairingController::OnConnectToService( |
+ scoped_refptr<device::BluetoothSocket> socket) { |
+ socket_ = socket; |
+ |
+ socket_->Receive( |
+ kReceiveSize, |
+ base::Bind(&BluetoothControllerPairingController::OnReceiveComplete, |
+ ptr_factory_.GetWeakPtr()), |
+ base::Bind(&BluetoothControllerPairingController::OnReceiveError, |
+ ptr_factory_.GetWeakPtr())); |
+} |
+ |
+void BluetoothControllerPairingController::OnSendComplete(int bytes_sent) {} |
+ |
+void BluetoothControllerPairingController::OnReceiveComplete( |
+ int bytes, scoped_refptr<net::IOBuffer> io_buffer) { |
+ proto_decoder_->DecodeIOBuffer(bytes, io_buffer); |
+ |
+ socket_->Receive( |
+ kReceiveSize, |
+ base::Bind(&BluetoothControllerPairingController::OnReceiveComplete, |
+ ptr_factory_.GetWeakPtr()), |
+ base::Bind(&BluetoothControllerPairingController::OnReceiveError, |
+ ptr_factory_.GetWeakPtr())); |
+} |
+ |
+void BluetoothControllerPairingController::OnError() { |
+ ChangeStage(STAGE_DEVICE_NOT_FOUND); |
achuithb
2014/08/20 21:52:32
Shouldn't we be logging something here? Why STAGE_
Zachary Kuznia
2014/08/21 00:42:07
Added TODO and explanation.
|
+} |
+ |
+void BluetoothControllerPairingController::OnErrorWithMessage( |
+ const std::string& message) { |
+ LOG(ERROR) << message; |
+ Reset(); |
achuithb
2014/08/20 21:52:31
Is this the best thing to do? What happens if we r
Zachary Kuznia
2014/08/21 00:42:06
Added TODO and explanation.
|
+} |
+ |
+void BluetoothControllerPairingController::OnConnectError( |
+ device::BluetoothDevice::ConnectErrorCode error_code) { |
+ if (device_->IsPaired()) { |
achuithb
2014/08/20 21:52:32
Could you add some comments here - why is connect
Zachary Kuznia
2014/08/21 00:42:06
Added comment.
|
+ // Connection error is fine, as long as pairing was successful. |
+ OnConnect(); |
+ } else { |
+ ChangeStage(STAGE_ESTABLISHING_CONNECTION_ERROR); |
+ } |
+} |
+ |
+void BluetoothControllerPairingController::OnReceiveError( |
+ device::BluetoothSocket::ErrorReason reason, |
+ const std::string& error_message) { |
+ LOG(ERROR) << reason << ", " << error_message; |
+ Reset(); |
+} |
+ |
+// ControllerPairingController: |
achuithb
2014/08/20 21:52:32
Remove this comment
Zachary Kuznia
2014/08/21 00:42:06
Done.
|
+void BluetoothControllerPairingController::AddObserver( |
+ ControllerPairingController::Observer* observer) { |
+ observers_.AddObserver(observer); |
+} |
+ |
+void BluetoothControllerPairingController::RemoveObserver( |
+ ControllerPairingController::Observer* observer) { |
+ observers_.RemoveObserver(observer); |
+} |
+ |
+ControllerPairingController::Stage |
+BluetoothControllerPairingController::GetCurrentStage() { |
achuithb
2014/08/20 21:52:31
This should be current_stage() and defined in the
Zachary Kuznia
2014/08/21 00:42:06
This is virtual, as discussed.
|
+ return current_stage_; |
+} |
+ |
+void BluetoothControllerPairingController::StartPairing() { |
+ DCHECK(current_stage_ == STAGE_NONE || |
+ current_stage_ == STAGE_DEVICE_NOT_FOUND || |
+ current_stage_ == STAGE_ESTABLISHING_CONNECTION_ERROR || |
+ current_stage_ == STAGE_HOST_ENROLLMENT_ERROR); |
+ bool bluetooth_available = |
achuithb
2014/08/20 21:52:32
This variable seems unnecessary - why not inline i
Zachary Kuznia
2014/08/21 00:42:06
Done.
|
+ device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable(); |
+ // TODO(zork): Add a stage for no bluetooth. |
achuithb
2014/08/20 21:52:32
Let's add bug-ids for all TODOs.
Zachary Kuznia
2014/08/21 00:42:07
Done.
|
+ if (!bluetooth_available) |
+ ChangeStage(STAGE_DEVICE_NOT_FOUND); |
+ |
+ device::BluetoothAdapterFactory::GetAdapter( |
+ base::Bind(&BluetoothControllerPairingController::OnGetAdapter, |
+ ptr_factory_.GetWeakPtr())); |
+ |
+} |
+ |
+ControllerPairingController::DeviceIdList |
+BluetoothControllerPairingController::GetDiscoveredDevices() { |
+ DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY); |
+ return DeviceIdList(discovered_devices_.begin(), discovered_devices_.end()); |
+} |
+ |
+void BluetoothControllerPairingController::ChooseDeviceForPairing( |
+ const std::string& device_id) { |
+ DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY); |
+ CHECK(discovered_devices_.count(device_id)); |
achuithb
2014/08/20 21:52:31
Why CHECK?
Zachary Kuznia
2014/08/21 00:42:06
DCHECK now.
|
+ // TODO: Consider using stop instead of reset(). |
achuithb
2014/08/20 21:52:33
TODO(zork) + bug-id
Zachary Kuznia
2014/08/21 00:42:06
Done.
|
+ discovery_session_.reset(); |
+ device_ = adapter_->GetDevice(device_id); |
+ if (device_) { |
+ ChangeStage(STAGE_ESTABLISHING_CONNECTION); |
+ if (device_->IsPaired()) { |
+ OnConnect(); |
+ } else { |
+ device_->Connect( |
+ this, |
+ base::Bind(&BluetoothControllerPairingController::OnConnect, |
+ ptr_factory_.GetWeakPtr()), |
+ base::Bind(&BluetoothControllerPairingController::OnConnectError, |
+ ptr_factory_.GetWeakPtr())); |
+ } |
+ } else { |
+ ChangeStage(STAGE_ESTABLISHING_CONNECTION_ERROR); |
+ } |
+} |
+ |
+void BluetoothControllerPairingController::RepeatDiscovery() { |
+ CHECK(current_stage_ == STAGE_DEVICE_NOT_FOUND || |
achuithb
2014/08/20 21:52:33
Why CHECK and not DCHECK?
Zachary Kuznia
2014/08/21 00:42:06
Done.
|
+ current_stage_ == STAGE_ESTABLISHING_CONNECTION_ERROR || |
+ current_stage_ == STAGE_HOST_ENROLLMENT_ERROR); |
+ Reset(); |
+ StartPairing(); |
+} |
+ |
+std::string BluetoothControllerPairingController::GetConfirmationCode() { |
achuithb
2014/08/20 21:52:32
Return const std::string&
Zachary Kuznia
2014/08/21 00:42:07
This is virtual, as discussed.
|
+ DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION); |
+ DCHECK(!confirmation_code_.empty()); |
+ return confirmation_code_; |
+} |
+ |
+void BluetoothControllerPairingController::SetConfirmationCodeIsCorrect( |
+ bool correct) { |
+ DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION); |
+ if (correct) { |
+ device_->ConfirmPairing(); |
+ // Once pairing is confirmed, the connection will either be successful, or |
+ // fail. Either case is acceptable as long as the devices are paired. |
+ } else { |
+ device_->RejectPairing(); |
+ device_ = NULL; |
+ RepeatDiscovery(); |
+ } |
+} |
+ |
+void BluetoothControllerPairingController::OnAuthenticationDone( |
+ const chromeos::UserContext& user_context, |
+ content::BrowserContext* browser_context) { |
+ DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CREDENTIALS); |
+ |
+ // TODO: Get configuration from UI and send to Host |
+ |
+ // TODO: Get proper credentials. |
achuithb
2014/08/20 21:52:33
TODO(zork) + bug-id
Zachary Kuznia
2014/08/21 00:42:06
Done.
|
+ // For now, send a fake domain. |
+ pairing_api::PairDevices pair_devices; |
+ pair_devices.set_api_version(kPairingAPIVersion); |
+ pair_devices.mutable_parameters()->set_admin_access_token( |
+ kFakeEnrollmentDomain); |
+ |
+ int size = 0; |
+ scoped_refptr<net::IOBuffer> io_buffer( |
+ ProtoDecoder::SendPairDevices(pair_devices, &size)); |
+ |
+ socket_->Send( |
+ io_buffer, size, |
+ base::Bind(&BluetoothControllerPairingController::OnSendComplete, |
+ ptr_factory_.GetWeakPtr()), |
+ base::Bind(&BluetoothControllerPairingController::OnErrorWithMessage, |
+ ptr_factory_.GetWeakPtr())); |
+ ChangeStage(STAGE_HOST_ENROLLMENT_IN_PROGRESS); |
+} |
+ |
+void BluetoothControllerPairingController::StartSession() { |
+ DCHECK_EQ(current_stage_, STAGE_PAIRING_DONE); |
+ ChangeStage(STAGE_FINISHED); |
+} |
+ |
+// ProtoDecoder::Observer: |
achuithb
2014/08/20 21:52:32
Remove this comment
Zachary Kuznia
2014/08/21 00:42:06
Done.
|
+void BluetoothControllerPairingController::OnHostStatusMessage( |
+ const pairing_api::HostStatus& message) { |
+ if (got_initial_status_) { |
+ if (message.parameters().has_domain()) { |
+ if (message.parameters().domain() == kFakeEnrollmentDomain) { |
achuithb
2014/08/20 21:52:31
Where is this domain supposed to come from?
Zachary Kuznia
2014/08/21 00:42:06
Added a comment to explain.
|
+ pairing_api::CompleteSetup complete_setup; |
+ complete_setup.set_api_version(kPairingAPIVersion); |
+ // TODO: Get AddAnother from UI |
achuithb
2014/08/20 21:52:32
TODO(zork) + bug-id
Zachary Kuznia
2014/08/21 00:42:06
Done.
|
+ complete_setup.mutable_parameters()->set_add_another(false); |
+ |
+ int size = 0; |
+ scoped_refptr<net::IOBuffer> io_buffer( |
+ ProtoDecoder::SendCompleteSetup(complete_setup, &size)); |
+ |
+ socket_->Send( |
+ io_buffer, size, |
+ base::Bind(&BluetoothControllerPairingController::OnSendComplete, |
+ ptr_factory_.GetWeakPtr()), |
+ base::Bind( |
+ &BluetoothControllerPairingController::OnErrorWithMessage, |
achuithb
2014/08/20 21:52:31
Should we be retrying?
Zachary Kuznia
2014/08/21 00:42:06
No; if send fails, we'll have to restart the whole
|
+ ptr_factory_.GetWeakPtr())); |
+ ChangeStage(STAGE_PAIRING_DONE); |
+ } else { |
+ ChangeStage(STAGE_HOST_ENROLLMENT_ERROR); |
+ } |
+ } else { |
+ ChangeStage(STAGE_HOST_ENROLLMENT_ERROR); |
+ } |
+ } else { |
+ got_initial_status_ = true; |
+ |
+ // TODO: Check domain. |
+ |
+ // TODO: Handling updating stages. |
achuithb
2014/08/20 21:52:32
TODO(zork) + bug-id
Zachary Kuznia
2014/08/21 00:42:07
Done.
|
+ ChangeStage(STAGE_WAITING_FOR_CREDENTIALS); |
+ } |
+} |
+ |
+void BluetoothControllerPairingController::OnConfigureHostMessage( |
+ const pairing_api::ConfigureHost& message) { |
+ NOTREACHED(); |
+} |
+ |
+void BluetoothControllerPairingController::OnPairDevicesMessage( |
+ const pairing_api::PairDevices& message) { |
+ NOTREACHED(); |
+} |
+ |
+void BluetoothControllerPairingController::OnCompleteSetupMessage( |
+ const pairing_api::CompleteSetup& message) { |
+ NOTREACHED(); |
+} |
+ |
+void BluetoothControllerPairingController::OnErrorMessage( |
+ const pairing_api::Error& message) { |
+ LOG(ERROR) << message.parameters().code() << ", " << |
+ message.parameters().description(); |
+ ChangeStage(STAGE_HOST_ENROLLMENT_ERROR); |
+} |
+ |
+// device::BluetoothAdapter::Observer: |
achuithb
2014/08/20 21:52:32
REmove this comment
Zachary Kuznia
2014/08/21 00:42:06
Done.
|
+void BluetoothControllerPairingController::DeviceAdded( |
+ device::BluetoothAdapter* adapter, |
+ device::BluetoothDevice* device) { |
+ DCHECK_EQ(adapter, adapter_.get()); |
+ DeviceFound(device); |
+} |
+ |
+void BluetoothControllerPairingController::DeviceRemoved( |
+ device::BluetoothAdapter* adapter, |
+ device::BluetoothDevice* device) { |
+ DCHECK_EQ(adapter, adapter_.get()); |
+ DeviceLost(device); |
+} |
+ |
+// device::BluetoothDevice::PairingDelegate: |
achuithb
2014/08/20 21:52:32
REmove this comment
Zachary Kuznia
2014/08/21 00:42:06
Done.
|
+void BluetoothControllerPairingController::RequestPinCode( |
+ device::BluetoothDevice* device) { |
+ // Disallow unknown device. |
+ device->RejectPairing(); |
+} |
+ |
+void BluetoothControllerPairingController::RequestPasskey( |
+ device::BluetoothDevice* device) { |
+ // Disallow unknown device. |
+ device->RejectPairing(); |
+} |
+ |
+void BluetoothControllerPairingController::DisplayPinCode( |
+ device::BluetoothDevice* device, |
+ const std::string& pincode) { |
+ // Disallow unknown device. |
+ device->RejectPairing(); |
+} |
+ |
+void BluetoothControllerPairingController::DisplayPasskey( |
+ device::BluetoothDevice* device, |
+ uint32 passkey) { |
+ // Disallow unknown device. |
+ device->RejectPairing(); |
+} |
+ |
+void BluetoothControllerPairingController::KeysEntered( |
+ device::BluetoothDevice* device, |
+ uint32 entered) { |
+ // Disallow unknown device. |
+ device->RejectPairing(); |
+} |
+ |
+void BluetoothControllerPairingController::ConfirmPasskey( |
+ device::BluetoothDevice* device, |
+ uint32 passkey) { |
+ DCHECK_EQ(device, device_); |
+ confirmation_code_ = base::StringPrintf("%06d", passkey); |
+ ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION); |
+} |
+ |
+void BluetoothControllerPairingController::AuthorizePairing( |
+ device::BluetoothDevice* device) { |
+ // Disallow unknown device. |
+ device->RejectPairing(); |
+} |
+ |
+} // namespace pairing_chromeos |