summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Solovev <ivan.solovev@qt.io>2022-07-13 12:04:59 +0200
committerIvan Solovev <ivan.solovev@qt.io>2022-07-19 10:41:12 +0200
commit05bdb20de257f9ae40bc299075de17eaf582f128 (patch)
treed9e6b4640b3b7d854b10601bd6f4011076d872e0
parentfc51af238505d31b704395227c0ff101e47e93e8 (diff)
Windows Bluetooth: move DeviceWatcher wrapper into a separate header
The DeviceWatcher wrapper seems to be useful not only in QBluetoothLocalDevice implementation, but also for device discovery. This patch moves it to a separate header, so that it can be reused. The class' API is also refactored to suit for more general usecases. This patch also applies the changes to QBluetoothLocalDevice. As a drive-by: clean-up some includes and namespaces in QBluetoothLocalDevice implementation. Task-number: QTBUG-103263 Change-Id: I470c6eab4810065c03d5905032f4288fa9d6de8e Reviewed-by: Juha Vuolle <juha.vuolle@insta.fi> Reviewed-by: Oliver Wolff <oliver.wolff@qt.io> (cherry picked from commit 761a059d5a5ef97e97039f3a34b3a7f92944f1f0)
-rw-r--r--src/bluetooth/CMakeLists.txt1
-rw-r--r--src/bluetooth/qbluetoothdevicewatcher_winrt.cpp145
-rw-r--r--src/bluetooth/qbluetoothdevicewatcher_winrt_p.h105
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_winrt.cpp81
4 files changed, 275 insertions, 57 deletions
diff --git a/src/bluetooth/CMakeLists.txt b/src/bluetooth/CMakeLists.txt
index 909a26f4..865bf154 100644
--- a/src/bluetooth/CMakeLists.txt
+++ b/src/bluetooth/CMakeLists.txt
@@ -223,6 +223,7 @@ elseif(QT_FEATURE_winrt_bt)
qbluetoothsocket_winrt.cpp qbluetoothsocket_winrt_p.h
qbluetoothutils_winrt.cpp qbluetoothutils_winrt_p.h
qlowenergycontroller_winrt.cpp qlowenergycontroller_winrt_p.h
+ qbluetoothdevicewatcher_winrt.cpp qbluetoothdevicewatcher_winrt_p.h
DEFINES
QT_WINRT_BLUETOOTH
LIBRARIES
diff --git a/src/bluetooth/qbluetoothdevicewatcher_winrt.cpp b/src/bluetooth/qbluetoothdevicewatcher_winrt.cpp
new file mode 100644
index 00000000..336e3cdc
--- /dev/null
+++ b/src/bluetooth/qbluetoothdevicewatcher_winrt.cpp
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbluetoothdevicewatcher_winrt_p.h"
+
+#include <winrt/Windows.Foundation.Collections.h>
+
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::Devices::Enumeration;
+
+QT_BEGIN_NAMESPACE
+
+QBluetoothDeviceWatcherWinRT::QBluetoothDeviceWatcherWinRT(int id, winrt::hstring selector)
+ : m_id(id),
+ m_watcher(DeviceInformation::CreateWatcher(selector))
+{
+ qRegisterMetaType<winrt::hstring>("winrt::hstring");
+}
+
+QBluetoothDeviceWatcherWinRT::QBluetoothDeviceWatcherWinRT(int id, winrt::hstring selector,
+ winrt::Windows::Devices::Enumeration::DeviceInformationKind kind)
+ : m_id(id)
+{
+ qRegisterMetaType<winrt::hstring>("winrt::hstring");
+ const winrt::param::iterable<winrt::hstring> extra {};
+ m_watcher = DeviceInformation::CreateWatcher(selector, extra, kind);
+}
+
+QBluetoothDeviceWatcherWinRT::~QBluetoothDeviceWatcherWinRT()
+{
+ if (m_watcher && m_initialized) {
+ stop();
+ unsubscribeFromEvents();
+ m_initialized = false;
+ }
+}
+
+bool QBluetoothDeviceWatcherWinRT::init()
+{
+ if (!m_watcher) {
+ qWarning("Windows failed to create an instance of DeviceWatcher. "
+ "Detection of Bluetooth devices might not work correctly.");
+ return false;
+ }
+ if (!m_initialized) {
+ subscribeToEvents();
+ m_initialized = true;
+ }
+ return true;
+}
+
+void QBluetoothDeviceWatcherWinRT::start()
+{
+ if (m_watcher)
+ m_watcher.Start();
+}
+
+void QBluetoothDeviceWatcherWinRT::stop()
+{
+ if (m_watcher && canStop())
+ m_watcher.Stop();
+}
+
+void QBluetoothDeviceWatcherWinRT::subscribeToEvents()
+{
+ Q_ASSERT(m_watcher.Status() == DeviceWatcherStatus::Created);
+ // The callbacks are triggered from separate threads. So we capture
+ // thisPtr to make sure that the object is valid.
+ auto thisPtr = shared_from_this();
+ m_addedToken = m_watcher.Added([thisPtr](DeviceWatcher, const DeviceInformation &info) {
+ emit thisPtr->deviceAdded(info.Id(), thisPtr->m_id);
+ });
+ m_removedToken =
+ m_watcher.Removed([thisPtr](DeviceWatcher, const DeviceInformationUpdate &upd) {
+ emit thisPtr->deviceRemoved(upd.Id(), thisPtr->m_id);
+ });
+ m_updatedToken =
+ m_watcher.Updated([thisPtr](DeviceWatcher, const DeviceInformationUpdate &upd) {
+ emit thisPtr->deviceUpdated(upd.Id(), thisPtr->m_id);
+ });
+ // because of ambiguous declaration
+ using WinRtInspectable = winrt::Windows::Foundation::IInspectable;
+ m_enumerationToken =
+ m_watcher.EnumerationCompleted([thisPtr](DeviceWatcher, const WinRtInspectable &) {
+ emit thisPtr->enumerationCompleted(thisPtr->m_id);
+ });
+ m_stoppedToken = m_watcher.Stopped([thisPtr](DeviceWatcher, const WinRtInspectable &) {
+ emit thisPtr->watcherStopped(thisPtr->m_id);
+ });
+}
+
+void QBluetoothDeviceWatcherWinRT::unsubscribeFromEvents()
+{
+ m_watcher.Added(m_addedToken);
+ m_watcher.Removed(m_removedToken);
+ m_watcher.Updated(m_updatedToken);
+ m_watcher.EnumerationCompleted(m_enumerationToken);
+ m_watcher.Stopped(m_stoppedToken);
+}
+
+bool QBluetoothDeviceWatcherWinRT::canStop() const
+{
+ const auto status = m_watcher.Status();
+ // Also 'Aborted', but calling Stop() there is a no-op
+ return status == DeviceWatcherStatus::Started
+ || status == DeviceWatcherStatus::EnumerationCompleted;
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothdevicewatcher_winrt_p.h b/src/bluetooth/qbluetoothdevicewatcher_winrt_p.h
new file mode 100644
index 00000000..603227d7
--- /dev/null
+++ b/src/bluetooth/qbluetoothdevicewatcher_winrt_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBLUETOOTHDEVICEWATCHER_WINRT_P_H
+#define QBLUETOOTHDEVICEWATCHER_WINRT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/QObject>
+
+#include <private/qbluetoothutils_winrt_p.h>
+
+#include <winrt/base.h>
+#include <winrt/Windows.Devices.Enumeration.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBluetoothDeviceWatcherWinRT : public QObject,
+ public std::enable_shared_from_this<QBluetoothDeviceWatcherWinRT>
+{
+ Q_OBJECT
+public:
+ QBluetoothDeviceWatcherWinRT(int id, winrt::hstring selector);
+ QBluetoothDeviceWatcherWinRT(int id, winrt::hstring selector,
+ winrt::Windows::Devices::Enumeration::DeviceInformationKind kind);
+ ~QBluetoothDeviceWatcherWinRT();
+
+ bool init();
+ void start();
+ void stop();
+
+signals:
+ // The signals will be emitted from a separate thread,
+ // so we need to use Qt::QueuedConnection
+ void deviceAdded(winrt::hstring deviceId, int id);
+ void deviceRemoved(winrt::hstring deviceId, int id);
+ void deviceUpdated(winrt::hstring deviceId, int id);
+ void enumerationCompleted(int id);
+ void watcherStopped(int id);
+
+private:
+ void subscribeToEvents();
+ void unsubscribeFromEvents();
+ bool canStop() const;
+
+ const int m_id; // used to uniquely identify the wrapper
+ winrt::Windows::Devices::Enumeration::DeviceWatcher m_watcher = nullptr;
+ bool m_initialized = false;
+
+ winrt::event_token m_addedToken;
+ winrt::event_token m_removedToken;
+ winrt::event_token m_updatedToken;
+ winrt::event_token m_enumerationToken;
+ winrt::event_token m_stoppedToken;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBLUETOOTHDEVICEWATCHER_WINRT_P_H
diff --git a/src/bluetooth/qbluetoothlocaldevice_winrt.cpp b/src/bluetooth/qbluetoothlocaldevice_winrt.cpp
index cce19416..566562ce 100644
--- a/src/bluetooth/qbluetoothlocaldevice_winrt.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice_winrt.cpp
@@ -37,11 +37,12 @@
**
****************************************************************************/
-#include <qbluetoothutils_winrt_p.h>
+#include <private/qbluetoothutils_winrt_p.h>
#include "qbluetoothlocaldevice.h"
#include "qbluetoothaddress.h"
+#include "qbluetoothdevicewatcher_winrt_p.h"
#include "qbluetoothlocaldevice_p.h"
#include "qbluetoothutils_winrt_p.h"
@@ -50,20 +51,18 @@
#include <winrt/Windows.Devices.Enumeration.h>
#include <winrt/Windows.Devices.Bluetooth.h>
#include <winrt/Windows.Devices.Radios.h>
-#include <wrl.h>
-#include <QtCore/private/qfunctions_winrt_p.h>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QMutex>
#include <QtCore/QPointer>
#include <QtCore/QTimer>
-#include <QtCore/QMutex>
-#include <QtCore/QLoggingCategory>
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::Devices::Enumeration;
using namespace winrt::Windows::Devices::Bluetooth;
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
using namespace winrt::Windows::Devices::Radios;
QT_BEGIN_NAMESPACE
@@ -111,66 +110,35 @@ static RadioState windowsStateFromMode(QBluetoothLocalDevice::HostMode mode)
class AdapterManager;
-class WatcherWrapper : public QObject, public std::enable_shared_from_this<WatcherWrapper>
+class WatcherWrapper
{
- Q_OBJECT
public:
- WatcherWrapper(winrt::hstring selector) : mWatcher(DeviceInformation::CreateWatcher(selector))
+ // we do not really care about unique ids here
+ WatcherWrapper(winrt::hstring selector) :
+ mWatcher(std::make_shared<QBluetoothDeviceWatcherWinRT>(0, selector))
{
}
- ~WatcherWrapper()
- {
- if (mWatcher && mInitialized) {
- mWatcher.Stop();
- unsubscribeFromEvents();
- }
- }
template<typename AddedSlot, typename RemovedSlot>
- bool init(AdapterManager *manager, AddedSlot onAdded, RemovedSlot onRemoved)
+ void init(AdapterManager *manager, AddedSlot onAdded, RemovedSlot onRemoved)
{
if (!mWatcher) {
- qWarning() << "Windows failed to create an instance of DeviceWatcher. "
- << "QBluetoothLocalDevice might fail to provide some information.";
- return false;
+ qWarning("QBluetoothLocalDevice: failed to create device watcher!");
+ return;
}
- subscribeToEvents();
- connect(this, &WatcherWrapper::deviceAdded, manager, onAdded, Qt::QueuedConnection);
- connect(this, &WatcherWrapper::deviceRemoved, manager, onRemoved, Qt::QueuedConnection);
- mInitialized = true;
- mWatcher.Start();
- return true;
- }
-
-signals:
- void deviceAdded(winrt::hstring id);
- void deviceRemoved(winrt::hstring id);
+ QObject::connect(mWatcher.get(), &QBluetoothDeviceWatcherWinRT::deviceAdded,
+ manager, onAdded, Qt::QueuedConnection);
+ QObject::connect(mWatcher.get(), &QBluetoothDeviceWatcherWinRT::deviceRemoved,
+ manager, onRemoved, Qt::QueuedConnection);
-private:
- void subscribeToEvents()
- {
- // The callbacks are triggered from separate threads. So we capture
- // thisPtr to make sure that the object is valid.
- auto thisPtr = shared_from_this();
- mAddedToken = mWatcher.Added([thisPtr](DeviceWatcher, const DeviceInformation &info) {
- emit thisPtr->deviceAdded(info.Id());
- });
- mRemovedToken =
- mWatcher.Removed([thisPtr](DeviceWatcher, const DeviceInformationUpdate &upd) {
- emit thisPtr->deviceRemoved(upd.Id());
- });
- }
- void unsubscribeFromEvents()
- {
- mWatcher.Added(mAddedToken);
- mWatcher.Removed(mRemovedToken);
+ // This will also print a warning on failure.
+ if (mWatcher->init())
+ mWatcher->start();
}
- bool mInitialized = false;
- DeviceWatcher mWatcher = nullptr;
- winrt::event_token mAddedToken;
- winrt::event_token mRemovedToken;
+private:
+ std::shared_ptr<QBluetoothDeviceWatcherWinRT> mWatcher = nullptr;
};
/*
@@ -222,7 +190,7 @@ private:
void onStateChange(Radio radio);
Q_SLOT void tryResubscribeToStateChanges(winrt::hstring id, int numAttempts);
- std::shared_ptr<WatcherWrapper> mAdapterWatcher = nullptr;
+ std::unique_ptr<WatcherWrapper> mAdapterWatcher = nullptr;
QMutex mRadiosMutex;
// Key for this map is BluetoothAdapter Id, *not* Radio Id.
QMap<winrt::hstring, RadioInfo> mRadios;
@@ -230,9 +198,8 @@ private:
AdapterManager::AdapterManager() : QObject()
{
- qRegisterMetaType<winrt::hstring>("winrt::hstring");
const auto adapterSelector = BluetoothAdapter::GetDeviceSelector();
- mAdapterWatcher = std::make_shared<WatcherWrapper>(adapterSelector);
+ mAdapterWatcher = std::make_unique<WatcherWrapper>(adapterSelector);
mAdapterWatcher->init(this, &AdapterManager::onAdapterAdded, &AdapterManager::onAdapterRemoved);
}