| // Copyright 2016 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 "device/bluetooth/adapter.h" |
| |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/callback_helpers.h" |
| #include "base/memory/ptr_util.h" |
| #include "build/build_config.h" |
| #include "device/bluetooth/bluetooth_socket.h" |
| #include "device/bluetooth/device.h" |
| #include "device/bluetooth/discovery_session.h" |
| #include "device/bluetooth/public/cpp/bluetooth_uuid.h" |
| #include "device/bluetooth/public/mojom/connect_result_type_converter.h" |
| #include "device/bluetooth/server_socket.h" |
| #include "device/bluetooth/socket.h" |
| #include "mojo/public/cpp/bindings/pending_remote.h" |
| #include "mojo/public/cpp/bindings/self_owned_receiver.h" |
| |
| namespace bluetooth { |
| |
| Adapter::Adapter(scoped_refptr<device::BluetoothAdapter> adapter) |
| : adapter_(std::move(adapter)) { |
| adapter_->AddObserver(this); |
| } |
| |
| Adapter::~Adapter() { |
| adapter_->RemoveObserver(this); |
| adapter_ = nullptr; |
| } |
| |
| void Adapter::ConnectToDevice(const std::string& address, |
| ConnectToDeviceCallback callback) { |
| device::BluetoothDevice* device = adapter_->GetDevice(address); |
| |
| if (!device) { |
| std::move(callback).Run(mojom::ConnectResult::DEVICE_NO_LONGER_IN_RANGE, |
| /*device=*/mojo::NullRemote()); |
| return; |
| } |
| |
| auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); |
| device->CreateGattConnection( |
| base::BindOnce(&Adapter::OnGattConnected, weak_ptr_factory_.GetWeakPtr(), |
| copyable_callback), |
| base::BindOnce(&Adapter::OnConnectError, weak_ptr_factory_.GetWeakPtr(), |
| copyable_callback)); |
| } |
| |
| void Adapter::GetDevices(GetDevicesCallback callback) { |
| std::vector<mojom::DeviceInfoPtr> devices; |
| |
| for (const device::BluetoothDevice* device : adapter_->GetDevices()) { |
| mojom::DeviceInfoPtr device_info = |
| Device::ConstructDeviceInfoStruct(device); |
| devices.push_back(std::move(device_info)); |
| } |
| |
| std::move(callback).Run(std::move(devices)); |
| } |
| |
| void Adapter::GetInfo(GetInfoCallback callback) { |
| mojom::AdapterInfoPtr adapter_info = mojom::AdapterInfo::New(); |
| adapter_info->address = adapter_->GetAddress(); |
| adapter_info->name = adapter_->GetName(); |
| #if defined(OS_CHROMEOS) || defined(OS_LINUX) |
| adapter_info->system_name = adapter_->GetSystemName(); |
| #endif |
| adapter_info->initialized = adapter_->IsInitialized(); |
| adapter_info->present = adapter_->IsPresent(); |
| adapter_info->powered = adapter_->IsPowered(); |
| adapter_info->discoverable = adapter_->IsDiscoverable(); |
| adapter_info->discovering = adapter_->IsDiscovering(); |
| std::move(callback).Run(std::move(adapter_info)); |
| } |
| |
| void Adapter::SetClient(mojo::PendingRemote<mojom::AdapterClient> client, |
| SetClientCallback callback) { |
| client_.Bind(std::move(client)); |
| std::move(callback).Run(); |
| } |
| |
| void Adapter::SetDiscoverable(bool discoverable, |
| SetDiscoverableCallback callback) { |
| auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); |
| adapter_->SetDiscoverable( |
| discoverable, |
| base::BindOnce(&Adapter::OnSetDiscoverable, |
| weak_ptr_factory_.GetWeakPtr(), copyable_callback), |
| base::BindOnce(&Adapter::OnSetDiscoverableError, |
| weak_ptr_factory_.GetWeakPtr(), copyable_callback)); |
| } |
| |
| void Adapter::SetName(const std::string& name, SetNameCallback callback) { |
| auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); |
| adapter_->SetName( |
| name, |
| base::BindOnce(&Adapter::OnSetName, weak_ptr_factory_.GetWeakPtr(), |
| copyable_callback), |
| base::BindOnce(&Adapter::OnSetNameError, weak_ptr_factory_.GetWeakPtr(), |
| copyable_callback)); |
| } |
| |
| void Adapter::StartDiscoverySession(StartDiscoverySessionCallback callback) { |
| auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); |
| adapter_->StartDiscoverySession( |
| base::BindOnce(&Adapter::OnStartDiscoverySession, |
| weak_ptr_factory_.GetWeakPtr(), copyable_callback), |
| base::BindOnce(&Adapter::OnDiscoverySessionError, |
| weak_ptr_factory_.GetWeakPtr(), copyable_callback)); |
| } |
| |
| void Adapter::ConnectToServiceInsecurely( |
| const std::string& address, |
| const device::BluetoothUUID& service_uuid, |
| ConnectToServiceInsecurelyCallback callback) { |
| auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); |
| adapter_->GetDevice(address)->ConnectToServiceInsecurely( |
| service_uuid, |
| base::BindOnce(&Adapter::OnConnectToService, |
| weak_ptr_factory_.GetWeakPtr(), copyable_callback), |
| base::BindOnce(&Adapter::OnConnectToServiceError, |
| weak_ptr_factory_.GetWeakPtr(), copyable_callback)); |
| } |
| |
| void Adapter::CreateRfcommService(const std::string& service_name, |
| const device::BluetoothUUID& service_uuid, |
| CreateRfcommServiceCallback callback) { |
| device::BluetoothAdapter::ServiceOptions service_options; |
| service_options.name = std::make_unique<std::string>(service_name); |
| |
| auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); |
| adapter_->CreateRfcommService( |
| service_uuid, service_options, |
| base::BindOnce(&Adapter::OnCreateRfcommService, |
| weak_ptr_factory_.GetWeakPtr(), copyable_callback), |
| base::BindOnce(&Adapter::OnCreateRfcommServiceError, |
| weak_ptr_factory_.GetWeakPtr(), copyable_callback)); |
| } |
| |
| void Adapter::AdapterPresentChanged(device::BluetoothAdapter* adapter, |
| bool present) { |
| if (client_) |
| client_->PresentChanged(present); |
| } |
| |
| void Adapter::AdapterPoweredChanged(device::BluetoothAdapter* adapter, |
| bool powered) { |
| if (client_) |
| client_->PoweredChanged(powered); |
| } |
| |
| void Adapter::AdapterDiscoverableChanged(device::BluetoothAdapter* adapter, |
| bool discoverable) { |
| if (client_) |
| client_->DiscoverableChanged(discoverable); |
| } |
| |
| void Adapter::AdapterDiscoveringChanged(device::BluetoothAdapter* adapter, |
| bool discovering) { |
| if (client_) |
| client_->DiscoveringChanged(discovering); |
| } |
| |
| void Adapter::DeviceAdded(device::BluetoothAdapter* adapter, |
| device::BluetoothDevice* device) { |
| if (client_) { |
| auto device_info = Device::ConstructDeviceInfoStruct(device); |
| client_->DeviceAdded(std::move(device_info)); |
| } |
| } |
| |
| void Adapter::DeviceChanged(device::BluetoothAdapter* adapter, |
| device::BluetoothDevice* device) { |
| if (client_) { |
| auto device_info = Device::ConstructDeviceInfoStruct(device); |
| client_->DeviceChanged(std::move(device_info)); |
| } |
| } |
| |
| void Adapter::DeviceRemoved(device::BluetoothAdapter* adapter, |
| device::BluetoothDevice* device) { |
| if (client_) { |
| auto device_info = Device::ConstructDeviceInfoStruct(device); |
| client_->DeviceRemoved(std::move(device_info)); |
| } |
| } |
| |
| void Adapter::OnGattConnected( |
| ConnectToDeviceCallback callback, |
| std::unique_ptr<device::BluetoothGattConnection> connection) { |
| mojo::PendingRemote<mojom::Device> device; |
| Device::Create(adapter_, std::move(connection), |
| device.InitWithNewPipeAndPassReceiver()); |
| std::move(callback).Run(mojom::ConnectResult::SUCCESS, std::move(device)); |
| } |
| |
| void Adapter::OnConnectError( |
| ConnectToDeviceCallback callback, |
| device::BluetoothDevice::ConnectErrorCode error_code) { |
| std::move(callback).Run(mojo::ConvertTo<mojom::ConnectResult>(error_code), |
| /*device=*/mojo::NullRemote()); |
| } |
| |
| void Adapter::OnSetDiscoverable(SetDiscoverableCallback callback) { |
| std::move(callback).Run(/*success=*/true); |
| } |
| |
| void Adapter::OnSetDiscoverableError(SetDiscoverableCallback callback) { |
| std::move(callback).Run(/*success=*/false); |
| } |
| |
| void Adapter::OnSetName(SetNameCallback callback) { |
| std::move(callback).Run(/*success=*/true); |
| } |
| |
| void Adapter::OnSetNameError(SetNameCallback callback) { |
| std::move(callback).Run(/*success=*/false); |
| } |
| |
| void Adapter::OnStartDiscoverySession( |
| StartDiscoverySessionCallback callback, |
| std::unique_ptr<device::BluetoothDiscoverySession> session) { |
| mojo::PendingRemote<mojom::DiscoverySession> pending_session; |
| mojo::MakeSelfOwnedReceiver( |
| std::make_unique<DiscoverySession>(std::move(session)), |
| pending_session.InitWithNewPipeAndPassReceiver()); |
| std::move(callback).Run(std::move(pending_session)); |
| } |
| |
| void Adapter::OnDiscoverySessionError(StartDiscoverySessionCallback callback) { |
| std::move(callback).Run(/*session=*/mojo::NullRemote()); |
| } |
| |
| void Adapter::OnConnectToService( |
| ConnectToServiceInsecurelyCallback callback, |
| scoped_refptr<device::BluetoothSocket> socket) { |
| mojo::ScopedDataPipeProducerHandle receive_pipe_producer_handle; |
| mojo::ScopedDataPipeConsumerHandle receive_pipe_consumer_handle; |
| MojoResult result = |
| mojo::CreateDataPipe(/*options=*/nullptr, &receive_pipe_producer_handle, |
| &receive_pipe_consumer_handle); |
| if (result != MOJO_RESULT_OK) { |
| socket->Close(); |
| OnConnectToServiceError(std::move(callback), |
| "Failed to create receiving DataPipe."); |
| return; |
| } |
| |
| mojo::ScopedDataPipeProducerHandle send_pipe_producer_handle; |
| mojo::ScopedDataPipeConsumerHandle send_pipe_consumer_handle; |
| result = mojo::CreateDataPipe(/*options=*/nullptr, &send_pipe_producer_handle, |
| &send_pipe_consumer_handle); |
| if (result != MOJO_RESULT_OK) { |
| socket->Close(); |
| OnConnectToServiceError(std::move(callback), |
| "Failed to create sending DataPipe."); |
| return; |
| } |
| |
| mojo::PendingRemote<mojom::Socket> pending_socket; |
| mojo::MakeSelfOwnedReceiver( |
| std::make_unique<Socket>(std::move(socket), |
| std::move(receive_pipe_producer_handle), |
| std::move(send_pipe_consumer_handle)), |
| pending_socket.InitWithNewPipeAndPassReceiver()); |
| |
| mojom::ConnectToServiceResultPtr connect_to_service_result = |
| mojom::ConnectToServiceResult::New(); |
| connect_to_service_result->socket = std::move(pending_socket); |
| connect_to_service_result->receive_stream = |
| std::move(receive_pipe_consumer_handle); |
| connect_to_service_result->send_stream = std::move(send_pipe_producer_handle); |
| std::move(callback).Run(std::move(connect_to_service_result)); |
| } |
| |
| void Adapter::OnConnectToServiceError( |
| ConnectToServiceInsecurelyCallback callback, |
| const std::string& message) { |
| DLOG(ERROR) << "Failed to connect to service: '" << message << "'"; |
| std::move(callback).Run(/*result=*/nullptr); |
| } |
| |
| void Adapter::OnCreateRfcommService( |
| CreateRfcommServiceCallback callback, |
| scoped_refptr<device::BluetoothSocket> socket) { |
| mojo::PendingRemote<mojom::ServerSocket> pending_server_socket; |
| mojo::MakeSelfOwnedReceiver( |
| std::make_unique<ServerSocket>(std::move(socket)), |
| pending_server_socket.InitWithNewPipeAndPassReceiver()); |
| std::move(callback).Run(std::move(pending_server_socket)); |
| } |
| |
| void Adapter::OnCreateRfcommServiceError(CreateRfcommServiceCallback callback, |
| const std::string& message) { |
| LOG(ERROR) << "Failed to create service: '" << message << "'"; |
| std::move(callback).Run(/*server_socket=*/mojo::NullRemote()); |
| } |
| |
| } // namespace bluetooth |