Initial commit for bluetooth classic medium notified of adapter scan mode change.

PiperOrigin-RevId: 396955416
This commit is contained in:
jfcarroll
2021-09-15 16:55:07 -07:00
committed by Copybara-Service
parent 1a3b294407
commit 0de9bed4ca
9 changed files with 140 additions and 65 deletions
@@ -90,16 +90,18 @@ BluetoothAdapter::ScanMode BluetoothAdapter::GetScanMode() const {
// Synchronously sets the scan mode of the adapter, and returns true if the
// operation was a success.
// TODO(jcarroll): Setup an event for this and hook the bluetooth medium into
// the event to allow for updates.
bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) {
scan_mode_ = scan_mode;
if (scan_mode_changed_ != nullptr) {
scan_mode_changed_(scan_mode);
}
return true;
}
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getName()
// Returns an empty string on error
// TODO(b/184975123): replace with real implementation.
std::string BluetoothAdapter::GetName() const {
char *instanceID = GetGenericBluetoothAdapterInstanceID();
+23 -15
View File
@@ -25,60 +25,68 @@ namespace location {
namespace nearby {
namespace windows {
// Represents a Bluetooth adapter.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.bluetoothadapter?view=winrt-20348
using winrt::Windows::Devices::Bluetooth::IBluetoothAdapter;
// Represents a Bluetooth adapter.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.bluetoothadapter?view=winrt-20348
using winrt::Windows::Devices::Bluetooth::IBluetoothAdapter;
// Represents a radio device on the system.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.radios.radio?view=winrt-20348
using winrt::Windows::Devices::Radios::IRadio;
// Represents a radio device on the system.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.radios.radio?view=winrt-20348
using winrt::Windows::Devices::Radios::IRadio;
// Enumeration that describes possible radio states.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.radios.radiostate?view=winrt-20348
using winrt::Windows::Devices::Radios::RadioState;
// Enumeration that describes possible radio states.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.radios.radiostate?view=winrt-20348
using winrt::Windows::Devices::Radios::RadioState;
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html
class BluetoothAdapter : public api::BluetoothAdapter {
public:
BluetoothAdapter();
// TODO(b/184975123): replace with real implementation.
~BluetoothAdapter() override = default;
typedef std::function<void(api::BluetoothAdapter::ScanMode)> ScanModeCallback;
// Synchronously sets the status of the BluetoothAdapter to 'status', and
// returns true if the operation was a success.
bool SetStatus(Status status) override;
// Returns true if the BluetoothAdapter's current status is
// Status::Value::kEnabled.
bool IsEnabled() const override;
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode()
//
// Returns ScanMode::kUnknown on error.
ScanMode GetScanMode() const override;
// Synchronously sets the scan mode of the adapter, and returns true if the
// operation was a success.
bool SetScanMode(ScanMode scan_mode) override;
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getName()
// Returns an empty string on error
// TODO(b/184975123): replace with real implementation.
std::string GetName() const override;
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#setName(java.lang.String)
bool SetName(absl::string_view name) override;
// Returns BT MAC address assigned to this adapter.
std::string GetMacAddress() const override;
void SetOnScanModeChanged(ScanModeCallback callback) {
if (scan_mode_changed_ == nullptr) {
scan_mode_changed_ = callback;
}
}
private:
IBluetoothAdapter
windows_bluetooth_adapter_;
IBluetoothAdapter windows_bluetooth_adapter_;
IRadio windows_bluetooth_radio_;
char *GetGenericBluetoothAdapterInstanceID(void) const;
void find_and_replace(char *source, const char *strFind,
const char *strReplace) const;
ScanMode scan_mode_ = ScanMode::kNone;
ScanModeCallback scan_mode_changed_ = nullptr;
};
} // namespace windows
@@ -14,7 +14,7 @@
#include "platform/impl/windows/bluetooth_classic_medium.h"
#include <Windows.h>
#include <windows.h>
#include <stdio.h>
#include <codecvt>
@@ -42,16 +42,27 @@ namespace nearby {
namespace windows {
BluetoothClassicMedium::BluetoothClassicMedium(
const api::BluetoothAdapter& bluetoothAdapter)
: bluetooth_adapter_(
dynamic_cast<const BluetoothAdapter&>(bluetoothAdapter)) {
api::BluetoothAdapter& bluetoothAdapter)
: bluetooth_adapter_(dynamic_cast<BluetoothAdapter&>(bluetoothAdapter)) {
InitializeCriticalSection(&critical_section_);
InitializeDeviceWatcher();
bluetooth_adapter_.SetOnScanModeChanged(std::bind(
&BluetoothClassicMedium::OnScanModeChanged, this, std::placeholders::_1));
}
BluetoothClassicMedium::~BluetoothClassicMedium() {}
void BluetoothClassicMedium::OnScanModeChanged(
BluetoothAdapter::ScanMode scanMode) {
scan_mode_ = scanMode;
bool radioDiscoverable = bluetooth_adapter_.GetScanMode() ==
BluetoothAdapter::ScanMode::kConnectableDiscoverable;
bluetooth_server_socket_->SetScanMode(radioDiscoverable);
}
bool BluetoothClassicMedium::StartDiscovery(
BluetoothClassicMedium::DiscoveryCallback discovery_callback) {
EnterCriticalSection(&critical_section_);
@@ -117,6 +128,7 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
api::BluetoothDevice& remote_device, const std::string& service_uuid,
CancellationFlag* cancellation_flag) {
if (service_uuid.empty()) {
NEARBY_LOGS(ERROR) << __func__ << ": service_uuid not specified.";
return nullptr;
}
@@ -127,12 +139,15 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
// Must check for valid pattern as the guid constructor will throw on an
// invalid format
if (!regex_match(service_uuid, pattern)) {
NEARBY_LOGS(ERROR) << __func__
<< ": invalid service_uuid: " << service_uuid;
return nullptr;
}
winrt::guid service(service_uuid);
if (cancellation_flag == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": cancellation_flag not specified.";
return nullptr;
}
@@ -140,12 +155,15 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
dynamic_cast<BluetoothDevice*>(&remote_device);
if (currentDevice == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to get current device.";
return nullptr;
}
winrt::hstring deviceId = winrt::to_hstring(currentDevice->GetId());
if (!HaveAccess(deviceId)) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to gain access to device: "
<< winrt::to_string(deviceId);
return nullptr;
}
@@ -153,6 +171,7 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
GetRequestedService(currentDevice, service));
if (!CheckSdp(requestedService)) {
NEARBY_LOGS(ERROR) << __func__ << ": Invalid SDP.";
return nullptr;
}
@@ -221,6 +240,7 @@ RfcommDeviceService BluetoothClassicMedium::GetRequestedService(
if (rfcommServices.get().Services().Size() > 0) {
requestedService = rfcommServices.get().Services().GetAt(0);
} else {
NEARBY_LOGS(ERROR) << __func__ << ": No services found.";
return nullptr;
}
@@ -233,6 +253,7 @@ bool BluetoothClassicMedium::CheckSdp(RfcommDeviceService requestedService) {
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.rfcomm.rfcommdeviceservice.getsdprawattributesasync?view=winrt-20348
auto attributes = /*await*/ requestedService.GetSdpRawAttributesAsync();
if (!attributes.get().HasKey(Constants::SdpServiceNameAttributeId)) {
NEARBY_LOGS(ERROR) << __func__ << ": Missing SdpServiceNameAttributeId.";
return false;
}
@@ -242,6 +263,7 @@ bool BluetoothClassicMedium::CheckSdp(RfcommDeviceService requestedService) {
auto attributeType = attributeReader.ReadByte();
if (attributeType != Constants::SdpServiceNameAttributeType) {
NEARBY_LOGS(ERROR) << __func__ << ": Missing SdpServiceNameAttributeType.";
return false;
}
@@ -256,27 +278,37 @@ bool BluetoothClassicMedium::CheckSdp(RfcommDeviceService requestedService) {
// UUID.
//
// Returns nullptr error.
// TODO(b/184975123): replace with real implementation.
std::unique_ptr<api::BluetoothServerSocket>
BluetoothClassicMedium::ListenForService(const std::string& service_name,
const std::string& service_uuid) {
if (service_uuid.empty()) {
NEARBY_LOGS(ERROR) << __func__ << ": service_uuid was empty.";
return nullptr;
}
if (service_name.empty()) {
NEARBY_LOGS(ERROR) << __func__ << ": service_name was empty.";
return nullptr;
}
auto bluetooth_server_socket =
std::make_unique<location::nearby::windows::BluetoothServerSocket>();
std::make_unique<location::nearby::windows::BluetoothServerSocket>(
service_name, service_uuid);
bool radioDiscoverable =
bluetooth_adapter_.GetScanMode() ==
BluetoothAdapter::ScanMode::kConnectableDiscoverable;
if (bluetooth_server_socket == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to create the server socket.";
return nullptr;
}
bluetooth_server_socket->StartListening(service_name, service_uuid,
radioDiscoverable);
bool radioDiscoverable = bluetooth_adapter_.GetScanMode() ==
BluetoothAdapter::ScanMode::kConnectableDiscoverable;
Exception result = bluetooth_server_socket->StartListening(radioDiscoverable);
if (result.value != Exception::kSuccess) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to start listening.";
return nullptr;
}
return std::move(bluetooth_server_socket);
}
@@ -301,6 +333,9 @@ bool BluetoothClassicMedium::StartScanning() {
}
}
NEARBY_LOGS(ERROR)
<< __func__
<< ": Attempted to start scanning when watcher already started.";
return false;
}
@@ -309,7 +344,9 @@ bool BluetoothClassicMedium::StopScanning() {
device_watcher_.Stop();
return true;
}
NEARBY_LOGS(ERROR)
<< __func__
<< ": Attempted to stop scanning when watcher already stopped.";
return false;
}
@@ -16,10 +16,10 @@
#define PLATFORM_IMPL_WINDOWS_BLUETOOTH_CLASSIC_MEDIUM_H_
#include "platform/api/bluetooth_classic.h"
#include "platform/impl/windows/bluetooth_adapter.h"
#include "platform/impl/windows/bluetooth_classic_device.h"
#include "platform/impl/windows/bluetooth_classic_server_socket.h"
#include "platform/impl/windows/bluetooth_classic_socket.h"
#include "platform/impl/windows/bluetooth_adapter.h"
#include "platform/impl/windows/generated/winrt/Windows.Devices.Enumeration.h"
#include "platform/impl/windows/generated/winrt/Windows.Networking.Sockets.h"
#include "platform/impl/windows/generated/winrt/base.h"
@@ -84,8 +84,7 @@ using winrt::Windows::Storage::Streams::DataWriter;
// medium.
class BluetoothClassicMedium : public api::BluetoothClassicMedium {
public:
BluetoothClassicMedium() = default;
BluetoothClassicMedium(const api::BluetoothAdapter& bluetoothAdapter);
BluetoothClassicMedium(api::BluetoothAdapter& bluetoothAdapter);
~BluetoothClassicMedium() override;
@@ -129,7 +128,6 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium {
const std::string& service_name,
const std::string& service_uuid) override;
// TODO(b/184975123): replace with real implementation.
api::BluetoothDevice* GetRemoteDevice(
const std::string& mac_address) override;
@@ -139,6 +137,7 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium {
bool IsWatcherStarted();
bool IsWatcherRunning();
void InitializeDeviceWatcher();
void OnScanModeChanged(BluetoothAdapter::ScanMode scanMode);
// This is for a coroutine whose return type is winrt::fire_and_forget, which
// handles async operations which don't have any dependencies.
@@ -167,6 +166,10 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium {
DeviceWatcher device_watcher_ = nullptr;
std::unique_ptr<BluetoothSocket> bluetooth_socket_;
std::unique_ptr<BluetoothServerSocket> bluetooth_server_socket_;
std::string service_name_;
std::string service_uuid_;
// hstring is the only type of string winrt understands.
// https://docs.microsoft.com/en-us/uwp/cpp-ref-for-winrt/hstring
@@ -176,7 +179,9 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium {
// https://docs.microsoft.com/en-us/windows/win32/sync/critical-section-objects
CRITICAL_SECTION critical_section_;
BluetoothAdapter bluetooth_adapter_;
BluetoothAdapter& bluetooth_adapter_;
BluetoothAdapter::ScanMode scan_mode_;
};
} // namespace windows
@@ -14,8 +14,8 @@
#include "platform/impl/windows/bluetooth_classic_medium.h"
#include <windows.h>
#include <synchapi.h>
#include <windows.h>
#include <string>
@@ -31,8 +31,8 @@
// TODO(jfcarroll): Find a way to mock winrt components in order to properly
// unit test this. Once that's done, unit tests can be written, in a later C/L.
//
// CAUTION: THIS IS NOT A REAL TEST, THIS EXERCISES THE SCANNER, IT DOES NOT
// STOP AND IS INTENDED SOLELY FOR DEBUG AND DEMONSTRATION PURPOSES. DO NOT
// CAUTION: THIS IS NOT A REAL TEST, THIS EXERCISES THE SCANNER, IT MAY NOT
// STOP/HANG AND IS INTENDED SOLELY FOR DEBUG AND DEMONSTRATION PURPOSES. DO NOT
// ATTEMPT TO BUILD AND RUN THIS TEST ON GOOGLE3 YOU HAVE BEEN WARNED
using location::nearby::windows::BluetoothDevice;
@@ -88,6 +88,11 @@ TEST_F(BluetoothClassicMediumTests, ManualTest) {
std::make_unique<location::nearby::windows::BluetoothClassicMedium>(
bluetoothAdapter);
bluetoothAdapter.SetScanMode(location::nearby::windows::BluetoothAdapter::
ScanMode::kConnectableDiscoverable);
auto mode = bluetoothAdapter.GetScanMode();
bcm->StartDiscovery(
location::nearby::api::BluetoothClassicMedium::DiscoveryCallback{
.device_discovered_cb = device_discovered_cb,
@@ -26,7 +26,12 @@
namespace location {
namespace nearby {
namespace windows {
BluetoothServerSocket::BluetoothServerSocket() : rfcomm_provider_(nullptr) {
BluetoothServerSocket::BluetoothServerSocket(const std::string service_name,
const std::string service_uuid)
: radio_discoverable_(false),
service_name_(service_name),
service_uuid_(service_uuid),
rfcomm_provider_(nullptr) {
InitializeCriticalSection(&critical_section_);
}
@@ -61,12 +66,10 @@ std::unique_ptr<api::BluetoothSocket> BluetoothServerSocket::Accept() {
return nullptr;
}
Exception BluetoothServerSocket::StartListening(const std::string& service_name,
const std::string& service_uuid,
bool radioDiscoverable) {
Exception BluetoothServerSocket::StartListening(bool radioDiscoverable) {
EnterCriticalSection(&critical_section_);
winrt::guid service(service_uuid);
radio_discoverable_ = radioDiscoverable;
// Create the StreamSocketListener
stream_socket_listener_ = StreamSocketListener();
@@ -97,18 +100,19 @@ Exception BluetoothServerSocket::StartListening(const std::string& service_name,
try {
auto rfcommProviderRef =
RfcommServiceProvider::CreateAsync(RfcommServiceId::FromUuid(service))
RfcommServiceProvider::CreateAsync(
RfcommServiceId::FromUuid(winrt::guid(service_uuid_)))
.get();
rfcomm_provider_ = &rfcommProviderRef;
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
stream_socket_listener_
.BindServiceNameAsync(winrt::to_hstring(service_name.c_str()))
.BindServiceNameAsync(winrt::to_hstring(service_name_.c_str()))
.get();
// Set the SDP attributes and start Bluetooth advertising
InitializeServiceSdpAttributes(*rfcomm_provider_, service_name);
InitializeServiceSdpAttributes(*rfcomm_provider_, service_name_);
} catch (std::exception exception) {
// We will log and eat the exception since the caller
// expects nullptr if it fails
@@ -120,9 +124,18 @@ Exception BluetoothServerSocket::StartListening(const std::string& service_name,
return {Exception::kFailed};
}
StartAdvertising();
LeaveCriticalSection(&critical_section_);
return {Exception::kSuccess};
}
Exception BluetoothServerSocket::StartAdvertising() {
try {
rfcomm_provider_->StartAdvertising(
stream_socket_listener_.as<StreamSocketListener>(), radioDiscoverable);
stream_socket_listener_.as<StreamSocketListener>(),
radio_discoverable_);
} catch (std::exception exception) {
// We will log and eat the exception since the caller
// expects nullptr if it fails
@@ -134,11 +147,13 @@ Exception BluetoothServerSocket::StartListening(const std::string& service_name,
return {Exception::kFailed};
}
LeaveCriticalSection(&critical_section_);
return {Exception::kSuccess};
}
void BluetoothServerSocket::StopAdvertising() {
rfcomm_provider_->StopAdvertising();
}
void BluetoothServerSocket::InitializeServiceSdpAttributes(
RfcommServiceProvider rfcommProvider, std::string service_name) {
auto sdpWriter = DataWriter();
@@ -67,9 +67,9 @@ using winrt::Windows::Storage::Streams::UnicodeEncoding;
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html.
class BluetoothServerSocket : public api::BluetoothServerSocket {
public:
BluetoothServerSocket();
BluetoothServerSocket(const std::string service_name,
const std::string service_uuid);
// TODO(b/184975123): replace with real implementation.
~BluetoothServerSocket() override;
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#accept()
@@ -87,23 +87,34 @@ class BluetoothServerSocket : public api::BluetoothServerSocket {
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
Exception Close() override;
Exception StartListening(const std::string& service_name,
const std::string& service_uuid,
bool radioDiscoverable);
Exception StartListening(bool radioDiscoverable);
void SetScanMode(bool radioDiscoverable) {
radio_discoverable_ = radioDiscoverable;
StopAdvertising();
StartAdvertising();
}
private:
void InitializeServiceSdpAttributes(RfcommServiceProvider rfcommProvider,
std::string service_name);
Exception StartAdvertising();
void StopAdvertising();
// This is used to store sockets in case Accept hasn't been called. Once
// Accept has been called the socket is popped from the queue and returned to
// the caller
std::queue<std::unique_ptr<BluetoothSocket>> bluetooth_sockets_;
StreamSocketListener stream_socket_listener_;
winrt::event_token listener_token_;
CRITICAL_SECTION critical_section_;
bool closed_ = false;
bool radio_discoverable_;
const std::string service_name_;
const std::string service_uuid_;
RfcommServiceProvider* rfcomm_provider_;
};
@@ -70,7 +70,6 @@ class BluetoothSocket : public api::BluetoothSocket {
winrt::Windows::Networking::Sockets::StreamSocket streamSocket)
: windows_socket_(streamSocket) {}
// TODO(b/184975123): replace with real implementation.
~BluetoothSocket() override;
// NOTE:
@@ -88,7 +87,6 @@ class BluetoothSocket : public api::BluetoothSocket {
// Closes both input and output streams, marks Socket as closed.
// After this call object should be treated as not connected.
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
// TODO(b/184975123): replace with real implementation.
Exception Close() override;
// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#getRemoteDevice()
+2 -8
View File
@@ -56,7 +56,6 @@ std::unique_ptr<AtomicUint32> ImplementationPlatform::CreateAtomicUint32(
return absl::make_unique<windows::AtomicUint32>();
}
// TODO(b/184975123): replace with real implementation.
std::unique_ptr<CountDownLatch> ImplementationPlatform::CreateCountDownLatch(
std::int32_t count) {
return absl::make_unique<windows::CountDownLatch>(count);
@@ -89,35 +88,30 @@ std::unique_ptr<LogMessage> ImplementationPlatform::CreateLogMessage(
return absl::make_unique<windows::LogMessage>(file, line, severity);
}
// TODO(b/184975123): replace with real implementation.
std::unique_ptr<SubmittableExecutor>
ImplementationPlatform::CreateSingleThreadExecutor() {
return absl::make_unique<windows::SubmittableExecutor>();
}
// TODO(b/184975123): replace with real implementation.
std::unique_ptr<SubmittableExecutor>
ImplementationPlatform::CreateMultiThreadExecutor(
std::int32_t max_concurrency) {
return absl::make_unique<windows::SubmittableExecutor>();
return absl::make_unique<windows::SubmittableExecutor>(max_concurrency);
}
// TODO(b/184975123): replace with real implementation.
std::unique_ptr<ScheduledExecutor>
ImplementationPlatform::CreateScheduledExecutor() {
return absl::make_unique<windows::ScheduledExecutor>();
}
// TODO(b/184975123): replace with real implementation.
std::unique_ptr<BluetoothAdapter>
ImplementationPlatform::CreateBluetoothAdapter() {
return absl::make_unique<windows::BluetoothAdapter>();
}
// TODO(b/184975123): replace with real implementation.
std::unique_ptr<BluetoothClassicMedium>
ImplementationPlatform::CreateBluetoothClassicMedium(
BluetoothAdapter& adapter) {
nearby::api::BluetoothAdapter& adapter) {
return absl::make_unique<location::nearby::windows::BluetoothClassicMedium>(
adapter);
}