| 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..c90dfb7918b3d4345c79176f1987764001e68056
|
| --- /dev/null
|
| +++ b/components/pairing/bluetooth_controller_pairing_controller.cc
|
| @@ -0,0 +1,463 @@
|
| +// 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()
|
| + : current_stage_(STAGE_NONE),
|
| + got_initial_status_(false),
|
| + proto_decoder_(new ProtoDecoder(this)),
|
| + ptr_factory_(this) {
|
| +}
|
| +
|
| +BluetoothControllerPairingController::~BluetoothControllerPairingController() {
|
| + Reset();
|
| +}
|
| +
|
| +device::BluetoothDevice* BluetoothControllerPairingController::GetController() {
|
| + DCHECK(!controller_device_id_.empty());
|
| + device::BluetoothDevice* device = adapter_->GetDevice(controller_device_id_);
|
| + if (!device) {
|
| + LOG(ERROR) << "Lost connection to controller.";
|
| + ChangeStage(STAGE_ESTABLISHING_CONNECTION_ERROR);
|
| + }
|
| +
|
| + return device;
|
| +}
|
| +
|
| +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;
|
| + controller_device_id_.clear();
|
| + 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);
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + 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);
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + 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() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + adapter_->StartDiscoverySession(
|
| + base::Bind(&BluetoothControllerPairingController::OnStartDiscoverySession,
|
| + ptr_factory_.GetWeakPtr()),
|
| + base::Bind(&BluetoothControllerPairingController::OnError,
|
| + ptr_factory_.GetWeakPtr()));
|
| +}
|
| +
|
| +void BluetoothControllerPairingController::OnGetAdapter(
|
| + scoped_refptr<device::BluetoothAdapter> adapter) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(!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) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + 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() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + device::BluetoothDevice* device = GetController();
|
| + if (device) {
|
| + 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) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + 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) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + 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() {
|
| + // TODO(zork): Add a stage for initialization error. (http://crbug.com/405744)
|
| + LOG(ERROR) << "Pairing initialization failed";
|
| + Reset();
|
| +}
|
| +
|
| +void BluetoothControllerPairingController::OnErrorWithMessage(
|
| + const std::string& message) {
|
| + // TODO(zork): Add a stage for initialization error. (http://crbug.com/405744)
|
| + LOG(ERROR) << message;
|
| + Reset();
|
| +}
|
| +
|
| +void BluetoothControllerPairingController::OnConnectError(
|
| + device::BluetoothDevice::ConnectErrorCode error_code) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + device::BluetoothDevice* device = GetController();
|
| +
|
| + if (device && device->IsPaired()) {
|
| + // The connection attempt is only used to start the pairing between the
|
| + // devices. If the connection fails, it's not a problem as long as pairing
|
| + // was successful.
|
| + OnConnect();
|
| + }
|
| +}
|
| +
|
| +void BluetoothControllerPairingController::OnReceiveError(
|
| + device::BluetoothSocket::ErrorReason reason,
|
| + const std::string& error_message) {
|
| + LOG(ERROR) << reason << ", " << error_message;
|
| + Reset();
|
| +}
|
| +
|
| +void BluetoothControllerPairingController::AddObserver(
|
| + ControllerPairingController::Observer* observer) {
|
| + observers_.AddObserver(observer);
|
| +}
|
| +
|
| +void BluetoothControllerPairingController::RemoveObserver(
|
| + ControllerPairingController::Observer* observer) {
|
| + observers_.RemoveObserver(observer);
|
| +}
|
| +
|
| +ControllerPairingController::Stage
|
| +BluetoothControllerPairingController::GetCurrentStage() {
|
| + return current_stage_;
|
| +}
|
| +
|
| +void BluetoothControllerPairingController::StartPairing() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(current_stage_ == STAGE_NONE ||
|
| + current_stage_ == STAGE_DEVICE_NOT_FOUND ||
|
| + current_stage_ == STAGE_ESTABLISHING_CONNECTION_ERROR ||
|
| + current_stage_ == STAGE_HOST_ENROLLMENT_ERROR);
|
| + // TODO(zork): Add a stage for no bluetooth. (http://crbug.com/405744)
|
| + if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
|
| + ChangeStage(STAGE_DEVICE_NOT_FOUND);
|
| + return;
|
| + }
|
| +
|
| + 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);
|
| + DCHECK(discovered_devices_.count(device_id));
|
| + discovery_session_.reset();
|
| + controller_device_id_ = device_id;
|
| +
|
| + device::BluetoothDevice* device = GetController();
|
| +
|
| + 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()));
|
| + }
|
| + }
|
| +}
|
| +
|
| +void BluetoothControllerPairingController::RepeatDiscovery() {
|
| + DCHECK(current_stage_ == STAGE_DEVICE_NOT_FOUND ||
|
| + current_stage_ == STAGE_ESTABLISHING_CONNECTION_ERROR ||
|
| + current_stage_ == STAGE_HOST_ENROLLMENT_ERROR);
|
| + Reset();
|
| + StartPairing();
|
| +}
|
| +
|
| +std::string BluetoothControllerPairingController::GetConfirmationCode() {
|
| + 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);
|
| +
|
| + device::BluetoothDevice* device = GetController();
|
| + if (!device)
|
| + return;
|
| +
|
| + 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();
|
| + controller_device_id_.clear();
|
| + RepeatDiscovery();
|
| + }
|
| +}
|
| +
|
| +void BluetoothControllerPairingController::OnAuthenticationDone(
|
| + const chromeos::UserContext& user_context,
|
| + content::BrowserContext* browser_context) {
|
| + DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CREDENTIALS);
|
| +
|
| + // TODO(zork): Get configuration from UI and send to Host.
|
| + // (http://crbug.com/405744)
|
| +
|
| + // TODO(zork): Get proper credentials. (http://crbug.com/405744)
|
| + // 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:
|
| +void BluetoothControllerPairingController::OnHostStatusMessage(
|
| + const pairing_api::HostStatus& message) {
|
| + if (got_initial_status_) {
|
| + if (message.parameters().has_domain()) {
|
| + // TODO(zork): Remove this if we don't actually need the domain for UI.
|
| + // (http://crbug.com/405761)
|
| + if (message.parameters().domain() == kFakeEnrollmentDomain) {
|
| + pairing_api::CompleteSetup complete_setup;
|
| + complete_setup.set_api_version(kPairingAPIVersion);
|
| + // TODO(zork): Get AddAnother from UI (http://crbug.com/405757)
|
| + 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,
|
| + 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(zork): Check domain. (http://crbug.com/405761)
|
| +
|
| + // TODO(zork): Handling updating stages (http://crbug.com/405754).
|
| + 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);
|
| +}
|
| +
|
| +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);
|
| +}
|
| +
|
| +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) {
|
| + 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
|
|
|