4#include <private/qbluetoothutils_winrt_p.h>
13#include <winrt/Windows.Foundation.h>
14#include <winrt/Windows.Foundation.Collections.h>
15#include <winrt/Windows.Devices.Enumeration.h>
16#include <winrt/Windows.Devices.Bluetooth.h>
17#include <winrt/Windows.Devices.Radios.h>
19#include <QtCore/QCoreApplication>
20#include <QtCore/QElapsedTimer>
21#include <QtCore/QLoggingCategory>
22#include <QtCore/QMutex>
23#include <QtCore/QPointer>
24#include <QtCore/QTimer>
26using namespace winrt::Windows::Foundation;
27using namespace winrt::Windows::Foundation::Collections;
28using namespace winrt::Windows::Devices::Enumeration;
29using namespace winrt::Windows::Devices::Bluetooth;
30using namespace winrt::Windows::Devices::Radios;
39 using WinRtAsyncStatus = winrt::Windows::Foundation::AsyncStatus;
40 WinRtAsyncStatus status;
46 status = asyncInfo.Status();
48 if (status == WinRtAsyncStatus::Completed) {
49 result = asyncInfo.GetResults();
86 template<
typename AddedSlot,
typename RemovedSlot>
90 qWarning(
"QBluetoothLocalDevice: failed to create device watcher!");
100 if (mWatcher->init())
105 std::shared_ptr<QBluetoothDeviceWatcherWinRT> mWatcher =
nullptr;
147 Radio radio =
nullptr;
148 winrt::event_token stateToken;
150 RadioState currentState = RadioState::Unknown;
153 Radio getRadioFromAdapterId(winrt::hstring
id);
154 Q_SLOT void onAdapterAdded(winrt::hstring
id);
155 Q_SLOT void onAdapterRemoved(winrt::hstring
id);
156 void subscribeToStateChanges(RadioInfo &
info);
157 void unsubscribeFromStateChanges(RadioInfo &
info);
158 void onStateChange(Radio radio);
159 Q_SLOT void tryResubscribeToStateChanges(winrt::hstring
id,
int numAttempts);
161 Q_SLOT void onDeviceAdded(winrt::hstring
id);
162 Q_SLOT void onDeviceRemoved(winrt::hstring
id);
164 std::unique_ptr<WatcherWrapper> mAdapterWatcher =
nullptr;
165 std::unique_ptr<WatcherWrapper> mLeDevicesWatcher =
nullptr;
166 std::unique_ptr<WatcherWrapper> mClassicDevicesWatcher =
nullptr;
175 const auto adapterSelector = BluetoothAdapter::GetDeviceSelector();
176 mAdapterWatcher = std::make_unique<WatcherWrapper>(adapterSelector);
177 mAdapterWatcher->init(
this, &AdapterManager::onAdapterAdded, &AdapterManager::onAdapterRemoved);
182 const auto leSelector = BluetoothLEDevice::GetDeviceSelectorFromConnectionStatus(
183 BluetoothConnectionStatus::Connected);
184 mLeDevicesWatcher = std::make_unique<WatcherWrapper>(leSelector);
185 mLeDevicesWatcher->init(
this, &AdapterManager::onDeviceAdded, &AdapterManager::onDeviceRemoved);
187 const auto classicSelector = BluetoothDevice::GetDeviceSelectorFromConnectionStatus(
188 BluetoothConnectionStatus::Connected);
189 mClassicDevicesWatcher = std::make_unique<WatcherWrapper>(classicSelector);
190 mClassicDevicesWatcher->init(
this, &AdapterManager::onDeviceAdded,
191 &AdapterManager::onDeviceRemoved);
201 return mConnectedDevices;
220 const auto adapterId = client->mDeviceId;
222 auto &radioInfo = mRadios[adapterId];
223 radioInfo.numClients++;
230 Radio
r = getRadioFromAdapterId(adapterId);
236 info.currentState =
r.State();
237 subscribeToStateChanges(
info);
242 qCWarning(QT_BT_WINDOWS,
"Failed to subscribe to adapter state changes");
250 auto &radioInfo = mRadios[adapterId];
251 if (--radioInfo.numClients == 0) {
252 unsubscribeFromStateChanges(radioInfo);
253 mRadios.
remove(adapterId);
256 qCWarning(QT_BT_WINDOWS) <<
"Removing client for an unknown adapter id"
265 RadioAccessStatus status = RadioAccessStatus::Unspecified;
266 auto radio = mRadios[adapterId].radio;
271 if (!
res || status != RadioAccessStatus::Allowed) {
272 qCWarning(QT_BT_WINDOWS,
"Failed to update adapter state: SetStateAsync() failed!");
273 if (status == RadioAccessStatus::DeniedBySystem) {
274 qCWarning(QT_BT_WINDOWS) <<
"Check that the user has permissions to manipulate"
275 " the selected Bluetooth device";
282Radio AdapterManager::getRadioFromAdapterId(winrt::hstring
id)
285 bool res =
await(BluetoothAdapter::FromIdAsync(
id),
a);
295void AdapterManager::onStateChange(Radio radio)
298 for (
const auto &
key : mRadios.
keys()) {
300 if (
info.radio == radio) {
301 if (
info.currentState != radio.State()) {
302 info.currentState = radio.State();
317void AdapterManager::tryResubscribeToStateChanges(winrt::hstring
id,
int numAttempts)
323 if (mRadios[
id].radio !=
nullptr)
326 Radio
r = getRadioFromAdapterId(
id);
334 info.currentState =
r.State();
335 subscribeToStateChanges(
info);
340 qCDebug(QT_BT_WINDOWS,
"Trying to resubscribe for the state changes");
344 thisPtr->tryResubscribeToStateChanges(
id, numAttempts);
348 "Failed to resubscribe to the state changes after %d attempts!",
368 device.ConnectionStatus() == BluetoothConnectionStatus::Connected };
371 BluetoothLEDevice leDevice(
nullptr);
372 res =
await(BluetoothLEDevice::FromIdAsync(
id), leDevice, 5000);
373 if (
res && leDevice) {
375 leDevice.ConnectionStatus() == BluetoothConnectionStatus::Connected };
381void AdapterManager::onDeviceAdded(winrt::hstring
id)
386 if (!
info.address.isNull() &&
info.isConnected) {
401void AdapterManager::onDeviceRemoved(winrt::hstring
id)
404 if (!
info.address.isNull() && !
info.isConnected) {
415void AdapterManager::onAdapterAdded(winrt::hstring
id)
424void AdapterManager::onAdapterRemoved(winrt::hstring
id)
432 mRadios[
id].radio =
nullptr;
436void AdapterManager::subscribeToStateChanges(AdapterManager::RadioInfo &
info)
439 info.stateToken =
info.radio.StateChanged([thisPtr](Radio
r,
const auto &) {
443 thisPtr->onStateChange(
r);
448void AdapterManager::unsubscribeFromStateChanges(AdapterManager::RadioInfo &
info)
452 info.radio.StateChanged(
info.stateToken);
459 const auto btSelector = BluetoothAdapter::GetDeviceSelector();
460 DeviceInformationCollection deviceInfoCollection(
nullptr);
461 await(DeviceInformation::FindAllAsync(btSelector), deviceInfoCollection);
462 return deviceInfoCollection;
468 BluetoothLEDevice leDevice(
nullptr);
469 bool res =
await(BluetoothLEDevice::FromBluetoothAddressAsync(addr64), leDevice, 5000);
471 return leDevice.DeviceInformation().Pairing();
474 res =
await(BluetoothDevice::FromBluetoothAddressAsync(addr64),
device, 5000);
476 return device.DeviceInformation().Pairing();
482 :
public winrt::implements<PairingWorker, winrt::Windows::Foundation::IInspectable>
491 void onPairingRequested(DeviceInformationCustomPairing
const&,
492 DevicePairingRequestedEventArgs
args);
502 auto ref = get_strong();
508 DeviceInformationCustomPairing customPairing = pairingInfo.Custom();
509 auto token = customPairing.PairingRequested(
510 { get_weak(), &PairingWorker::onPairingRequested });
511 DevicePairingResult
result{
nullptr};
512 bool res =
await(customPairing.PairAsync(DevicePairingKinds::ConfirmOnly),
result, 30000);
513 customPairing.PairingRequested(
token);
514 if (!
res ||
result.Status() != DevicePairingResultStatus::Paired) {
522 const auto resultingPairingStatus =
q->pairingStatus(
addr);
525 emit q->pairingFinished(
addr, resultingPairingStatus);
530 DeviceUnpairingResult unpairingResult{
nullptr};
531 bool res =
await(pairingInfo.UnpairAsync(), unpairingResult, 10000);
532 if (!
res || unpairingResult.Status() != DeviceUnpairingResultStatus::Unpaired) {
543void PairingWorker::onPairingRequested(
const DeviceInformationCustomPairing &,
544 DevicePairingRequestedEventArgs
args)
546 if (
args.PairingKind() != DevicePairingKinds::ConfirmOnly) {
574 mPairingWorker = winrt::make_self<PairingWorker>(
q);
577 bool res =
await(BluetoothAdapter::GetDefaultAsync(), mAdapter);
578 if (
res && mAdapter) {
580 mDeviceId = mAdapter.DeviceId();
581 DeviceInformation devInfo(
nullptr);
582 res =
await(DeviceInformation::CreateFromIdAsync(mDeviceId), devInfo);
589 for (
const auto &devInfo : deviceInfoCollection) {
591 const bool res =
await(BluetoothAdapter::FromIdAsync(devInfo.Id()), adapter);
592 if (
res && adapter) {
594 if (adapterAddress ==
address) {
596 mDeviceId = adapter.DeviceId();
604 mMode = adapterManager->addClient(
this);
607 qCWarning(QT_BT_WINDOWS,
"Failed to create QBluetoothLocalDevice - no adapter found");
609 qCWarning(QT_BT_WINDOWS) <<
"Failed to create QBluetoothLocalDevice for address"
617 adapterManager->removeClient(mDeviceId);
623 return mAdapter !=
nullptr;
629 qCWarning(QT_BT_WINDOWS,
"Trying to update state for an uninitialized adapter");
633 if (desiredMode != mMode) {
639 RadioAccessStatus status = RadioAccessStatus::Unspecified;
640 bool res =
await(Radio::RequestAccessAsync(), status);
641 if (
res && status == RadioAccessStatus::Allowed) {
644 emit updateMode(mDeviceId, desiredMode);
646 qCWarning(QT_BT_WINDOWS,
"Failed to update adapter state: operation denied!");
651void QBluetoothLocalDevicePrivate::onAdapterRemoved(winrt::hstring
id)
653 if (
id == mDeviceId) {
654 qCDebug(QT_BT_WINDOWS,
"Current adapter is removed");
663void QBluetoothLocalDevicePrivate::onAdapterAdded(winrt::hstring
id)
665 if (
id == mDeviceId && !mAdapter) {
667 qCDebug(QT_BT_WINDOWS,
"Adapter reconnected - trying to restore QBluetoothLocalDevice");
668 const bool res =
await(BluetoothAdapter::FromIdAsync(mDeviceId), mAdapter);
669 if (!
res || !mAdapter)
670 qCWarning(QT_BT_WINDOWS,
"Failed to restore adapter");
676 if (
id == mDeviceId && mAdapter) {
710 qCDebug(QT_BT_WINDOWS) <<
"requestPairing() no change needed to pairing" <<
address;
714 currentPairingStatus));
718 qCDebug(QT_BT_WINDOWS) <<
"requestPairing() initiating (un)pairing" <<
address << pairing;
719 d->mPairingWorker->pairAsync(
address, pairing);
729 if (!pairingInfo || !pairingInfo.IsPaired())
732 const DevicePairingProtectionLevel protection = pairingInfo.ProtectionLevel();
733 if (protection == DevicePairingProtectionLevel::Encryption
734 || protection == DevicePairingProtectionLevel::EncryptionAndAuthentication)
742 d->updateAdapterState(
mode);
768 return d->mAdapterName;
781 if (deviceInfoCollection) {
782 for (
const auto &devInfo : deviceInfoCollection) {
784 const bool res =
await(BluetoothAdapter::FromIdAsync(devInfo.Id()), adapter);
785 if (
res && adapter) {
798#include "qbluetoothlocaldevice_winrt.moc"
IOBluetoothDevice * device
void adapterAdded(winrt::hstring id)
void deviceAdded(const QBluetoothAddress &address)
void deviceRemoved(const QBluetoothAddress &address)
void updateMode(winrt::hstring adapterId, QBluetoothLocalDevice::HostMode mode)
void modeChanged(winrt::hstring id, QBluetoothLocalDevice::HostMode mode)
QList< QBluetoothAddress > connectedDevices()
void adapterRemoved(winrt::hstring id)
QBluetoothLocalDevice::HostMode addClient(QBluetoothLocalDevicePrivate *client)
void removeClient(winrt::hstring adapterId)
void deviceAdded(winrt::hstring deviceId, int id)
void deviceRemoved(winrt::hstring deviceId, int id)
QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *, const QBluetoothAddress &=QBluetoothAddress())
~QBluetoothLocalDevicePrivate()
void powerOn()
Powers on the device after returning it to the hostMode() state, if it was powered off.
Pairing
This enum describes the pairing state between the two Bluetooth devices.
void requestPairing(const QBluetoothAddress &address, Pairing pairing)
Set the pairing status with address.
HostMode
This enum describes the most of the local Bluetooth device.
HostMode hostMode() const
Returns the current host mode of this local Bluetooth device.
void deviceConnected(const QBluetoothAddress &address)
Error
This enum describes errors that maybe returned.
QList< QBluetoothAddress > connectedDevices() const
QBluetoothLocalDevice(QObject *parent=nullptr)
Constructs a QBluetoothLocalDevice with parent.
QString name() const
Returns the name assgined by the user to this Bluetooth device.
static QList< QBluetoothHostInfo > allDevices()
Returns a list of all available local Bluetooth devices.
Pairing pairingStatus(const QBluetoothAddress &address) const
Returns the current bluetooth pairing status of address, if it's unpaired, paired,...
QBluetoothAddress address() const
Returns the MAC address of this Bluetooth device.
void deviceDisconnected(const QBluetoothAddress &address)
void setHostMode(QBluetoothLocalDevice::HostMode mode)
Sets the host mode of this local Bluetooth device to mode.
void hostModeStateChanged(QBluetoothLocalDevice::HostMode state)
The state of the host has transitioned to a different HostMode.
static void processEvents(QEventLoop::ProcessEventsFlags flags=QEventLoop::AllEvents)
Processes some pending events for the calling thread according to the specified flags.
bool removeOne(const AT &t)
void push_back(parameter_type t)
iterator insert(const Key &key, const T &value)
bool contains(const Key &key) const
size_type remove(const Key &key)
void unlock() noexcept
Unlocks this mutex locker.
void relock() noexcept
Relocks an unlocked mutex locker.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromStdString(const std::string &s)
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
bool singleShot
whether the timer is a single-shot timer
void init(AdapterManager *manager, AddedSlot onAdded, RemovedSlot onRemoved)
WatcherWrapper(winrt::hstring selector)
Combined button and popup list for selecting options.
void registerQBluetoothLocalDeviceMetaType()
static const int kMaximumAttempts
static RadioState windowsStateFromMode(QBluetoothLocalDevice::HostMode mode)
static DeviceInformationCollection getAvailableAdapters()
DeviceInformationPairing pairingInfoFromAddress(const QBluetoothAddress &address)
static QT_BEGIN_NAMESPACE bool await(IAsyncOperation< T > &&asyncInfo, T &result, uint timeout=0)
static QBluetoothLocalDevice::HostMode adjustHostMode(QBluetoothLocalDevice::HostMode mode)
static QBluetoothLocalDevice::HostMode modeFromWindowsBluetoothState(RadioState state)
static BluetoothInfo getBluetoothInfo(winrt::hstring id)
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
#define Q_ARG(Type, data)
GLboolean GLboolean GLboolean GLboolean a
[7]
GLbitfield GLuint64 timeout
[4]
GLuint GLuint64EXT address
GLdouble GLdouble GLdouble GLdouble q
unsigned long long quint64
QFileInfo info(fileName)
[8]
QFileSelector selector
[1]
QNetworkAccessManager manager
QBluetoothAddress address
PairingWorker(QBluetoothLocalDevice *device)
void pairAsync(const QBluetoothAddress &addr, QBluetoothLocalDevice::Pairing pairing)
bool contains(const AT &t) const noexcept
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent