Define BluetoothPairing API for Nearby Platform Library and add implementation on Windows platform

PiperOrigin-RevId: 528510444
This commit is contained in:
Qin Wang
2023-05-01 10:36:59 -07:00
committed by Copybara-Service
parent 46e4b3eca7
commit e46bfb52d0
8 changed files with 508 additions and 74 deletions
+42
View File
@@ -16,7 +16,9 @@
#define PLATFORM_PUBLIC_BLUETOOTH_CLASSIC_H_
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
@@ -126,6 +128,36 @@ class BluetoothServerSocket final {
std::shared_ptr<api::BluetoothServerSocket> impl_;
};
// Opaque wrapper for a BluetoothPairing.
class BluetoothPairing final {
public:
explicit BluetoothPairing(
std::unique_ptr<api::BluetoothPairing> bluetooth_pairing)
: impl_(std::move(bluetooth_pairing)) {}
bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) {
return impl_->InitiatePairing(std::move(pairing_cb));
}
bool FinishPairing(std::optional<absl::string_view> pin_code) {
return impl_->FinishPairing(pin_code);
}
bool CancelPairing() { return impl_->CancelPairing(); }
bool Unpair() { return impl_->Unpair(); }
bool IsPaired() { return impl_->IsPaired(); }
// Returns reference to platform implementation.
// This is used to communicate with platform code, and for debugging
// purposes.
api::BluetoothPairing* GetImpl() { return impl_.get(); }
private:
std::unique_ptr<api::BluetoothPairing> impl_;
};
// Container of operations that can be performed over the Bluetooth Classic
// medium.
class BluetoothClassicMedium final
@@ -147,6 +179,7 @@ class BluetoothClassicMedium final
absl::AnyInvocable<void(BluetoothDevice& device)> device_lost_cb =
DefaultCallback<BluetoothDevice&>();
};
struct DeviceDiscoveryInfo {
BluetoothDevice device;
};
@@ -239,6 +272,15 @@ class BluetoothClassicMedium final
impl_->ListenForService(service_name, service_uuid));
}
// Return a Bluetooth pairing instance to handle the pairing process with the
// remote device.
std::unique_ptr<BluetoothPairing> CreatePairing(
BluetoothDevice& remote_device) {
std::unique_ptr<api::BluetoothPairing> bluetooth_pairing =
impl_->CreatePairing(remote_device.GetImpl());
return std::make_unique<BluetoothPairing>(std::move(bluetooth_pairing));
}
bool IsValid() const { return impl_ != nullptr; }
api::BluetoothClassicMedium& GetImpl() { return *impl_; }
@@ -16,8 +16,11 @@
#define PLATFORM_API_BLUETOOTH_CLASSIC_H_
#include <memory>
#include <optional>
#include <string>
#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/exception.h"
@@ -89,6 +92,105 @@ class BluetoothServerSocket {
virtual Exception Close() = 0;
};
// https://developer.android.com/reference/com/google/android/things/bluetooth/PairingParams
//
// Encapsulates the data for a particular pairing attempt.
// The caller can use it to determine the pairing approach and choose a suitable
// way to obtain user consent to conclude the pairing process.
struct PairingParams {
// Pairing type for this pairing attempt.
// The Pairing type is based on the User Interface capabilities of both
// the pairing devices, and determines the process of pairing.
// `kConstent`: the user is expected to consent to the pairing process.
// `kDisplayPasskey`: the user is notified of a pairing passkey.
// `kDisplayPin`: same as kDisplayPasskey, but different pairing key format.
// `kConfirmPasskey`: the user must confirm pairing after verifying a passkey.
// `kRequestPin`: the user is supposed to enter a pin to confirm pairing.
enum class PairingType {
kUnknown = 0,
kConsent = 1,
kDisplayPasskey = 2,
kDisplayPin = 3,
kConfirmPasskey = 4,
kRequestPin = 5,
kLast,
};
PairingType pairing_type;
// Pairing pin to notify the user for the pairing process.
// If not relevant to the current pairing process, it's empty.
std::string passkey;
};
// https://developer.android.com/reference/com/google/android/things/bluetooth/BluetoothPairingCallback
//
// This callback is invoked during the Bluetooth pairing process and
// contains all the relevant pairing information required for pairing.
struct BluetoothPairingCallback {
// https://developer.android.com/reference/com/google/android/things/bluetooth/BluetoothPairingCallback.PairingError
enum class PairingError {
kUnknown = 0,
kAuthCanceled = 1, /* failed because we canceled the pairing process. */
kAuthFailed = 2, /* failed with pins did not match, or no response. */
kAuthRejected = 3, /* failed with the remote device rejected pairing. */
kAuthTimeout = 4, /* failed with authentication timeout. */
kFailed = 5, /* failed with no explicit reason. */
kRepeatedAttempts = 6, /* failed with many repeated attempts. */
kLast,
};
// Invoked when successfully paired with a device.
absl::AnyInvocable<void()> on_paired_cb = DefaultCallback<>();
// Invoked when pairing with a device is canceled or fails.
absl::AnyInvocable<void(BluetoothPairingCallback::PairingError error)>
on_pairing_error_cb =
DefaultCallback<BluetoothPairingCallback::PairingError>();
// Invoked when the pairing process has been initiated with a remote
// Bluetooth device.
absl::AnyInvocable<void(PairingParams pairingParams)>
on_pairing_initiated_cb = DefaultCallback<PairingParams>();
};
// This class is responsible for handling Bluetooth pairing with a remote
// BluetoothDevice.
// DCHECK_CALLED_ON_VALID_SEQUENCE
class BluetoothPairing {
public:
virtual ~BluetoothPairing() = default;
// https://developer.android.com/reference/com/google/android/things/bluetooth/BluetoothConnectionManager#initiatepairing
// https://developer.android.com/reference/com/google/android/things/bluetooth/BluetoothConnectionManager#registerpairingcallback
//
// Initiate Bluetooth pairing process with a remote device.
// Register a BluetoothPairingCallback to listen for Bluetooth pairing events
// Such as incoming pairing request, devices paired etc.
virtual bool InitiatePairing(BluetoothPairingCallback pairing_cb) = 0;
// https://developer.android.com/reference/com/google/android/things/bluetooth/BluetoothConnectionManager#finishpairing
//
// Invoke this function to finish the pairing process with the remote device.
// Should be called only after receiving a callback from onPairingInitiated.
// Pin is needed for PairingType::kRequestPin
virtual bool FinishPairing(std::optional<absl::string_view> pin_code) = 0;
// https://developer.android.com/reference/com/google/android/things/bluetooth/BluetoothConnectionManager#cancelpairing
//
// Cancel an ongoing pairing process with a remote device.
virtual bool CancelPairing() = 0;
// https://developer.android.com/reference/com/google/android/things/bluetooth/BluetoothConnectionManager#unpair
//
// Destroys the existing pairing/bond with the remote device.
virtual bool Unpair() = 0;
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getBondState()
//
// Get the pairing state of the remote device.
virtual bool IsPaired() = 0;
};
// Container of operations that can be performed over the Bluetooth Classic
// medium.
class BluetoothClassicMedium {
@@ -174,6 +276,14 @@ class BluetoothClassicMedium {
virtual std::unique_ptr<BluetoothServerSocket> ListenForService(
const std::string& service_name, const std::string& service_uuid) = 0;
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createBond()
//
// Start the bonding (pairing) process with the remote device.
// Return a Bluetooth pairing instance to handle the pairing process with the
// remote device.
virtual std::unique_ptr<BluetoothPairing> CreatePairing(
BluetoothDevice& remote_device) = 0;
virtual BluetoothDevice* GetRemoteDevice(const std::string& mac_address) = 0;
virtual void AddObserver(Observer* observer) = 0;
@@ -271,6 +271,12 @@ BluetoothClassicMedium::ListenForService(const std::string& service_name,
return socket;
}
std::unique_ptr<api::BluetoothPairing> BluetoothClassicMedium::CreatePairing(
api::BluetoothDevice& remote_device) {
// TODO(b/279964840): Add g3 implementation for BluetoothPairing.
return nullptr;
}
api::BluetoothDevice* BluetoothClassicMedium::GetRemoteDevice(
const std::string& mac_address) {
auto& env = MediumEnvironment::Instance();
@@ -233,6 +233,11 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium {
const std::string& service_name, const std::string& service_uuid) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Return a Bluetooth pairing instance to handle the pairing process with the
// remote device.
std::unique_ptr<api::BluetoothPairing> CreatePairing(
api::BluetoothDevice& remote_device) override;
api::BluetoothDevice* GetRemoteDevice(
const std::string& mac_address) override;
@@ -19,6 +19,7 @@
#include <codecvt>
#include <fstream>
#include <functional>
#include <locale>
#include <map>
#include <memory>
@@ -29,10 +30,12 @@
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/cancellation_flag_listener.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/windows/bluetooth_adapter.h"
#include "internal/platform/implementation/windows/bluetooth_classic_device.h"
#include "internal/platform/implementation/windows/bluetooth_classic_server_socket.h"
#include "internal/platform/implementation/windows/bluetooth_classic_socket.h"
#include "internal/platform/implementation/windows/bluetooth_pairing.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Bluetooth.Rfcomm.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Bluetooth.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Enumeration.h"
@@ -45,7 +48,6 @@
namespace nearby {
namespace windows {
namespace {
using winrt::Windows::Foundation::IInspectable;
using winrt::Windows::Foundation::Collections::IMapView;
@@ -336,6 +338,37 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
}
}
std::unique_ptr<api::BluetoothPairing> BluetoothClassicMedium::CreatePairing(
api::BluetoothDevice& remote_device) {
NEARBY_LOGS(VERBOSE) << __func__ << ": Start to createPairing with device: "
<< remote_device.GetMacAddress();
try {
winrt::Windows::Devices::Bluetooth::BluetoothDevice bluetooth_device =
winrt::Windows::Devices::Bluetooth::BluetoothDevice::
FromBluetoothAddressAsync(
mac_address_string_to_uint64(remote_device.GetMacAddress()))
.get();
winrt::Windows::Devices::Enumeration::DeviceInformationCustomPairing
custom_pairing =
bluetooth_device.DeviceInformation().Pairing().Custom();
if (custom_pairing) {
return std::make_unique<BluetoothPairing>(bluetooth_device,
custom_pairing);
}
NEARBY_LOGS(VERBOSE) << __func__
<< ": Failed to get DeviceInformationCustomPairing.";
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << " : Failed to create pairing. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to create pairing. WinRT exception: "
<< error.code() << ": "
<< winrt::to_string(error.message());
}
return nullptr;
}
bool BluetoothClassicMedium::HaveAccess(winrt::hstring device_id) {
if (device_id.empty()) {
return false;
@@ -146,6 +146,11 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium {
api::BluetoothDevice* GetRemoteDevice(
const std::string& mac_address) override;
// Return a Bluetooth pairing instance to handle the pairing process with the
// remote device.
std::unique_ptr<api::BluetoothPairing> CreatePairing(
api::BluetoothDevice& remote_device) override;
void AddObserver(Observer* observer) override {
// TODO(b/269521993): Implement.
}
@@ -14,7 +14,20 @@
#include "internal/platform/implementation/windows/bluetooth_pairing.h"
#include <windows.h>
#include <exception>
#include <optional>
#include <string>
#include <utility>
#include "absl/log/check.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/windows/generated/winrt/impl/Windows.Devices.Enumeration.0.h"
#include "internal/platform/logging.h"
#include "winrt/Windows.Devices.Bluetooth.h"
#include "winrt/Windows.Devices.Enumeration.h"
#include "winrt/Windows.Foundation.Collections.h"
#include "winrt/base.h"
@@ -23,93 +36,294 @@ namespace nearby {
namespace windows {
namespace {
using ::winrt::Windows::Devices::Bluetooth::BluetoothDevice;
using ::winrt::Windows::Devices::Enumeration::DeviceInformationCustomPairing;
using ::winrt::Windows::Devices::Enumeration::DevicePairingKinds;
using ::winrt::Windows::Devices::Enumeration::DevicePairingProtectionLevel;
using ::winrt::Windows::Devices::Enumeration::DevicePairingRequestedEventArgs;
using ::winrt::Windows::Devices::Enumeration::DevicePairingResult;
using ::winrt::Windows::Devices::Enumeration::DevicePairingResultStatus;
using ::winrt::Windows::Devices::Enumeration::DeviceUnpairingResult;
using ::winrt::Windows::Devices::Enumeration::DeviceUnpairingResultStatus;
using ::winrt::Windows::Foundation::IAsyncOperation;
using PairingError = ::nearby::api::BluetoothPairingCallback::PairingError;
using PairingType = ::nearby::api::PairingParams::PairingType;
} // namespace
BluetoothPairing::BluetoothPairing(
DeviceInformationCustomPairing& custom_pairing)
: custom_pairing_(custom_pairing) {}
BluetoothDevice bluetooth_device,
DeviceInformationCustomPairing custom_pairing)
: bluetooth_device_(bluetooth_device), custom_pairing_(custom_pairing) {
NEARBY_LOGS(VERBOSE) << __func__
<< ": BluetoothPairing is created for device.";
}
BluetoothPairing::~BluetoothPairing() = default;
void BluetoothPairing::StartPairing() {
NEARBY_LOGS(VERBOSE) << "Bluetooth_pairing start pairing";
pairing_requested_token_ = custom_pairing_.PairingRequested(
{this, &BluetoothPairing::OnPairingRequested});
IAsyncOperation<DevicePairingResult> pairing_operation =
custom_pairing_.PairAsync(DevicePairingKinds::ConfirmOnly |
DevicePairingKinds::ProvidePin |
DevicePairingKinds::ConfirmPinMatch,
DevicePairingProtectionLevel::None);
DevicePairingResult pairing_result = pairing_operation.get();
if (pairing_result != nullptr) {
OnPair(pairing_result);
BluetoothPairing::~BluetoothPairing() {
if (pairing_requested_token_) {
custom_pairing_.PairingRequested(
std::exchange(pairing_requested_token_, {}));
}
CancelPairing();
NEARBY_LOGS(VERBOSE) << __func__
<< ": BluetoothPairing is destroyed for device.";
}
bool BluetoothPairing::InitiatePairing(
api::BluetoothPairingCallback pairing_cb) {
NEARBY_LOGS(VERBOSE) << __func__ << ": Start to initiate pairing process.";
try {
pairing_requested_token_ = custom_pairing_.PairingRequested(
{this, &BluetoothPairing::OnPairingRequested});
if (!pairing_requested_token_) {
NEARBY_LOGS(VERBOSE) << __func__
<< " Failed to registered pairing callback.";
return false;
}
pairing_callback_ = std::move(pairing_cb);
DevicePairingResult pairing_result =
custom_pairing_
.PairAsync(DevicePairingKinds::ConfirmOnly |
DevicePairingKinds::ProvidePin |
DevicePairingKinds::ConfirmPinMatch |
DevicePairingKinds::DisplayPin,
DevicePairingProtectionLevel::None)
.get();
OnPair(pairing_result);
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to initiate pairing. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to initiate pairing. WinRT exception: "
<< error.code() << ": "
<< winrt::to_string(error.message());
}
return false;
}
bool BluetoothPairing::FinishPairing(
std::optional<absl::string_view> pin_code) {
NEARBY_LOGS(VERBOSE) << __func__ << "Start to finish pairing.";
try {
if (!pairing_requested_) {
NEARBY_LOGS(VERBOSE) << __func__ << "No pairing requested.";
return false;
}
if (!pairing_deferral_) {
NEARBY_LOGS(VERBOSE) << __func__ << "No ongoing pairing process.";
return false;
}
if (expecting_pin_code_) {
if (!pin_code.has_value()) {
NEARBY_LOGS(INFO) << __func__ << " Failed to get pin code";
return false;
}
expecting_pin_code_ = false;
auto pin_hstring = winrt::to_hstring(std::string(pin_code.value()));
pairing_requested_.Accept(pin_hstring);
} else {
pairing_requested_.Accept();
}
pairing_deferral_.Complete();
NEARBY_LOGS(VERBOSE) << "Successfully finished pairing.";
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to finish pairing. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to finish pairing. WinRT exception: "
<< error.code() << ": "
<< winrt::to_string(error.message());
}
return false;
}
bool BluetoothPairing::CancelPairing() {
NEARBY_LOGS(VERBOSE) << __func__
<< "Start to cancel ongoing pairing process.";
try {
if (!pairing_deferral_) {
NEARBY_LOGS(VERBOSE) << __func__ << "No ongoing pairing process.";
return true;
}
// There is no way to explicitly cancel an in-progress pairing on Windows as
// DevicePairingRequestedEventArgs has no Cancel() method.
// Our approach is to complete the deferral, without accepting,
// which results in a RejectedByHandler result status.
// |was_cancelled_| is set so that OnPair(), which is called when the
// deferral is completed, will know that cancellation was the actual result.
was_cancelled_ = true;
pairing_deferral_.Complete();
NEARBY_LOGS(VERBOSE) << __func__ << "Canceled ongoing pairing process.";
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to cancel ongoing pairing "
<< "process. exception: " << exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to cancel ongoing pairing process. "
<< "WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
}
return false;
}
bool BluetoothPairing::Unpair() {
NEARBY_LOGS(VERBOSE) << __func__ << ": Start to unpair with remote device.";
try {
if (!IsPaired()) {
NEARBY_LOGS(VERBOSE) << __func__ << " : Remote device Was not paired.";
return true;
}
DeviceUnpairingResult unpairing_result =
bluetooth_device_.DeviceInformation().Pairing().UnpairAsync().get();
if (unpairing_result.Status() == DeviceUnpairingResultStatus::Unpaired) {
NEARBY_LOGS(VERBOSE) << __func__ << ": Unpaired with remote device.";
return true;
}
NEARBY_LOGS(VERBOSE) << __func__
<< ": Failed to unpaired with remote device.";
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to unpaired with device. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to unpaired with device. WinRT exception: "
<< error.code() << ": "
<< winrt::to_string(error.message());
}
return false;
}
bool BluetoothPairing::IsPaired() {
try {
bool is_paired = bluetooth_device_.DeviceInformation().Pairing().IsPaired();
NEARBY_LOGS(INFO) << __func__ << (is_paired ? "True" : "False");
return is_paired;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to get IsPaired. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to get IsPaired. WinRT exception: "
<< error.code() << ": "
<< winrt::to_string(error.message());
}
return false;
}
void BluetoothPairing::OnPairingRequested(
DeviceInformationCustomPairing custom_pairing,
DevicePairingRequestedEventArgs pairing_requested) {
NEARBY_LOGS(INFO) << "BluetoothPairing::OnPairingRequested()";
DevicePairingKinds pairing_kind = pairing_requested.PairingKind();
switch (pairing_kind) {
case DevicePairingKinds::ProvidePin:
NEARBY_LOGS(INFO) << "DevicePairingKind: RequestPinCode.";
pairing_requested.Accept();
return;
case DevicePairingKinds::ConfirmOnly:
NEARBY_LOGS(INFO) << "DevicePairingKind: ConfirmOnly.";
pairing_requested.Accept();
break;
case DevicePairingKinds::ConfirmPinMatch:
NEARBY_LOGS(INFO) << "DevicePairingKind: Confirm Pin Match "
<< pairing_requested.Pin().c_str();
pairing_requested.Accept();
break;
default:
NEARBY_LOGS(INFO) << "Unsupported DevicePairingKind = "
<< static_cast<int>(pairing_kind);
break;
NEARBY_LOGS(VERBOSE) << __func__ << "Requested to pair.";
try {
DevicePairingKinds pairing_kind = pairing_requested.PairingKind();
pairing_requested_ = pairing_requested;
pairing_deferral_ = pairing_requested.GetDeferral();
api::PairingParams params;
switch (pairing_kind) {
case DevicePairingKinds::ProvidePin:
NEARBY_LOGS(INFO) << __func__ << "DevicePairingKind: RequestPinCode.";
expecting_pin_code_ = true;
params.pairing_type = PairingType::kRequestPin;
pairing_callback_.on_pairing_initiated_cb(params);
return;
case DevicePairingKinds::ConfirmOnly:
NEARBY_LOGS(INFO) << __func__ << "DevicePairingKind: ConfirmOnly.";
params.pairing_type = PairingType::kConsent;
pairing_callback_.on_pairing_initiated_cb(params);
return;
case DevicePairingKinds::ConfirmPinMatch:
NEARBY_LOGS(INFO) << __func__
<< "DevicePairingKind: Confirm Pin Match.";
params.pairing_type = PairingType::kConfirmPasskey;
params.passkey = winrt::to_string(pairing_requested.Pin());
pairing_callback_.on_pairing_initiated_cb(params);
return;
default:
params.pairing_type = PairingType::kUnknown;
NEARBY_LOGS(INFO) << __func__ << "Unsupported DevicePairingKind:"
<< static_cast<int>(pairing_kind);
break;
}
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to request to pair with device. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR)
<< __func__
<< ": Failed to request to pair with device. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
}
pairing_callback_.on_pairing_error_cb(PairingError::kFailed);
}
void BluetoothPairing::OnPair(DevicePairingResult& pairing_result) {
DevicePairingResultStatus status = pairing_result.Status();
switch (status) {
case DevicePairingResultStatus::AlreadyPaired:
case DevicePairingResultStatus::Paired:
NEARBY_LOGS(ERROR) << "Pairing Result Status: Paired.";
return;
case DevicePairingResultStatus::PairingCanceled:
NEARBY_LOGS(ERROR) << "Pairing Result Status: Pairing Canceled.";
return;
case DevicePairingResultStatus::AuthenticationFailure:
NEARBY_LOGS(ERROR) << "Pairing Result Status: Authentication Failure.";
return;
case DevicePairingResultStatus::ConnectionRejected:
case DevicePairingResultStatus::RejectedByHandler:
NEARBY_LOGS(ERROR) << "Pairing Result Status: Authentication Rejected.";
return;
case DevicePairingResultStatus::AuthenticationTimeout:
NEARBY_LOGS(ERROR) << "Pairing Result Status: Authentication Timeout.";
return;
case DevicePairingResultStatus::Failed:
NEARBY_LOGS(ERROR) << "Pairing Result Status: Failed.";
return;
case DevicePairingResultStatus::OperationAlreadyInProgress:
NEARBY_LOGS(ERROR) << "Pairing Result Status: Operatio In Progress.";
return;
default:
NEARBY_LOGS(ERROR) << "Pairing Result Status: Failed.";
return;
try {
DevicePairingResultStatus status = pairing_result.Status();
NEARBY_LOGS(INFO) << __func__
<< "Pairing Result Status: " << static_cast<int>(status);
if (was_cancelled_ &&
status == DevicePairingResultStatus::RejectedByHandler) {
// See comment in CancelPairing() for explanation of why was_cancelled_
// is used.
status = DevicePairingResultStatus::PairingCanceled;
}
switch (status) {
case DevicePairingResultStatus::AlreadyPaired:
case DevicePairingResultStatus::Paired:
NEARBY_LOGS(ERROR) << __func__ << "Pairing Result Status: Paired.";
pairing_callback_.on_paired_cb();
return;
case DevicePairingResultStatus::PairingCanceled:
NEARBY_LOGS(ERROR) << __func__
<< "Pairing Result Status: Pairing Canceled.";
pairing_callback_.on_pairing_error_cb(PairingError::kAuthCanceled);
return;
case DevicePairingResultStatus::AuthenticationFailure:
NEARBY_LOGS(ERROR) << __func__
<< "Pairing Result Status: Authentication Failure.";
pairing_callback_.on_pairing_error_cb(PairingError::kAuthFailed);
return;
case DevicePairingResultStatus::ConnectionRejected:
case DevicePairingResultStatus::RejectedByHandler:
NEARBY_LOGS(ERROR) << __func__
<< "Pairing Result Status: Authentication Rejected.";
pairing_callback_.on_pairing_error_cb(PairingError::kAuthRejected);
return;
case DevicePairingResultStatus::AuthenticationTimeout:
NEARBY_LOGS(ERROR) << __func__
<< "Pairing Result Status: Authentication Timeout.";
pairing_callback_.on_pairing_error_cb(PairingError::kAuthTimeout);
return;
case DevicePairingResultStatus::Failed:
NEARBY_LOGS(ERROR) << __func__ << "Pairing Result Status: Failed.";
pairing_callback_.on_pairing_error_cb(PairingError::kFailed);
return;
case DevicePairingResultStatus::OperationAlreadyInProgress:
NEARBY_LOGS(ERROR) << __func__
<< "Pairing Result Status: Operation In Progress.";
pairing_callback_.on_pairing_error_cb(PairingError::kRepeatedAttempts);
return;
default:
break;
}
NEARBY_LOGS(ERROR) << __func__ << "Pairing Result Status: Failed.";
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to get Pairing Result Status. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to get Pairing Result Status."
<< " WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
}
pairing_callback_.on_pairing_error_cb(PairingError::kFailed);
}
} // namespace windows
@@ -15,27 +15,35 @@
#ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_BLUETOOTH_PAIRING_H_
#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_BLUETOOTH_PAIRING_H_
#include <guiddef.h>
#include <windows.h>
#include <string>
#include <optional>
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "winrt/Windows.Devices.Bluetooth.h"
#include "winrt/Windows.Devices.Enumeration.h"
#include "winrt/Windows.Foundation.Collections.h"
#include "winrt/base.h"
namespace nearby {
namespace windows {
class BluetoothPairing {
class BluetoothPairing : public api::BluetoothPairing {
public:
explicit BluetoothPairing(
::winrt::Windows::Devices::Enumeration::DeviceInformationCustomPairing&
::winrt::Windows::Devices::Bluetooth::BluetoothDevice bluetooth_device,
::winrt::Windows::Devices::Enumeration::DeviceInformationCustomPairing
custom_pairing);
BluetoothPairing(const BluetoothPairing&) = default;
BluetoothPairing& operator=(const BluetoothPairing&) = default;
~BluetoothPairing() override;
~BluetoothPairing();
// Initiates the pairing procedure.
void StartPairing();
bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) override;
bool FinishPairing(std::optional<absl::string_view> pin_code) override;
bool CancelPairing() override;
bool Unpair() override;
bool IsPaired() override;
private:
void OnPairingRequested(
@@ -48,9 +56,20 @@ class BluetoothPairing {
pairing_result);
// WinRT objects
::winrt::Windows::Devices::Bluetooth::BluetoothDevice bluetooth_device_;
::winrt::Windows::Devices::Enumeration::DeviceInformationCustomPairing
custom_pairing_;
::winrt::event_token pairing_requested_token_;
::winrt::Windows::Devices::Enumeration::DevicePairingRequestedEventArgs
pairing_requested_ = nullptr;
::winrt::Windows::Foundation::Deferral pairing_deferral_ = nullptr;
api::BluetoothPairingCallback pairing_callback_;
// Boolean indicating whether the device is currently pairing and expecting a
// PIN Code to be returned.
bool expecting_pin_code_ = false;
bool was_cancelled_ = false;
};
} // namespace windows