1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com>
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtBluetooth module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 #ifndef QBLUETOOTHDEVICEDISCOVERYAGENT_P_H
42 #define QBLUETOOTHDEVICEDISCOVERYAGENT_P_H
43 
44 //
45 //  W A R N I N G
46 //  -------------
47 //
48 // This file is not part of the Qt API.  It exists purely as an
49 // implementation detail.  This header file may change from version to
50 // version without notice, or even be removed.
51 //
52 // We mean it.
53 //
54 
55 #include "qbluetoothdevicediscoveryagent.h"
56 #ifdef QT_ANDROID_BLUETOOTH
57 #include <QtAndroidExtras/QAndroidJniObject>
58 #include "android/devicediscoverybroadcastreceiver_p.h"
59 #include <QtCore/QTimer>
60 #endif
61 
62 #ifdef Q_OS_DARWIN
63 #include "osx/btdelegates_p.h"
64 #include "osx/btraii_p.h"
65 #endif // Q_OS_DARWIN
66 
67 #include <QtCore/QVariantMap>
68 
69 #include <QtBluetooth/QBluetoothAddress>
70 #include <QtBluetooth/QBluetoothLocalDevice>
71 
72 #if QT_CONFIG(bluez)
73 #include "bluez/bluez5_helper_p.h"
74 
75 class OrgBluezManagerInterface;
76 class OrgBluezAdapterInterface;
77 class OrgFreedesktopDBusObjectManagerInterface;
78 class OrgFreedesktopDBusPropertiesInterface;
79 class OrgBluezAdapter1Interface;
80 class OrgBluezDevice1Interface;
81 
82 QT_BEGIN_NAMESPACE
83 class QDBusVariant;
84 QT_END_NAMESPACE
85 #endif
86 
87 #ifdef QT_WIN_BLUETOOTH
88 QT_BEGIN_NAMESPACE
89 class QThread;
90 
91 class ThreadWorkerDeviceDiscovery : public QObject
92 {
93     Q_OBJECT
94 signals:
95     void discoveryCompleted(const QVariant res);
96 };
97 
98 QT_END_NAMESPACE
99 
100 #elif defined(QT_WINRT_BLUETOOTH)
101 #include <QtCore/QPointer>
102 #include <QtCore/QTimer>
103 
104 using ManufacturerData = QHash<quint16, QByteArray>;
105 Q_DECLARE_METATYPE(ManufacturerData)
106 #endif
107 
108 QT_BEGIN_NAMESPACE
109 
110 #ifdef QT_WINRT_BLUETOOTH
111 class QWinRTBluetoothDeviceDiscoveryWorker;
112 #endif
113 
114 class QBluetoothDeviceDiscoveryAgentPrivate
115 #if defined(QT_ANDROID_BLUETOOTH) || defined(QT_WINRT_BLUETOOTH) || defined(QT_WIN_BLUETOOTH) \
116             || defined(Q_OS_DARWIN)
117     : public QObject
118 #if defined(Q_OS_MACOS)
119     , public DarwinBluetooth::DeviceInquiryDelegate
120 #endif // Q_OS_MACOS
121 {
122     Q_OBJECT
123 #else // BlueZ
124 {
125 #endif
126     Q_DECLARE_PUBLIC(QBluetoothDeviceDiscoveryAgent)
127 public:
128     QBluetoothDeviceDiscoveryAgentPrivate(
129             const QBluetoothAddress &deviceAdapter,
130             QBluetoothDeviceDiscoveryAgent *parent);
131     ~QBluetoothDeviceDiscoveryAgentPrivate();
132 
133     void start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods);
134     void stop();
135     bool isActive() const;
136 
137 #if QT_CONFIG(bluez)
138     void _q_deviceFound(const QString &address, const QVariantMap &dict);
139     void _q_propertyChanged(const QString &name, const QDBusVariant &value);
140     void _q_InterfacesAdded(const QDBusObjectPath &object_path,
141                             InterfaceList interfaces_and_properties);
142     void _q_discoveryFinished();
143     void _q_discoveryInterrupted(const QString &path);
144     void _q_PropertiesChanged(const QString &interface,
145                               const QString &path,
146                               const QVariantMap &changed_properties,
147                               const QStringList &invalidated_properties);
148     void _q_extendedDeviceDiscoveryTimeout();
149 #endif
150 
151 private:
152     QList<QBluetoothDeviceInfo> discoveredDevices;
153     QBluetoothDeviceDiscoveryAgent::InquiryType inquiryType;
154 
155     QBluetoothDeviceDiscoveryAgent::Error lastError;
156     QString errorString;
157 
158 #ifdef QT_ANDROID_BLUETOOTH
159 private slots:
160     void processSdpDiscoveryFinished();
161     void processDiscoveredDevices(const QBluetoothDeviceInfo &info, bool isLeResult);
162     friend void QtBluetoothLE_leScanResult(JNIEnv *, jobject, jlong, jobject);
163     void stopLowEnergyScan();
164 
165 private:
166     void startLowEnergyScan();
167 
168     DeviceDiscoveryBroadcastReceiver *receiver;
169     QBluetoothAddress m_adapterAddress;
170     short m_active;
171     QAndroidJniObject adapter;
172     QAndroidJniObject leScanner;
173     QTimer *leScanTimeout;
174 
175     bool pendingCancel, pendingStart;
176 #elif QT_CONFIG(bluez)
177     QBluetoothAddress m_adapterAddress;
178     bool pendingCancel;
179     bool pendingStart;
180     OrgBluezManagerInterface *manager = nullptr;
181     OrgBluezAdapterInterface *adapter = nullptr;
182     OrgFreedesktopDBusObjectManagerInterface *managerBluez5 = nullptr;
183     OrgBluezAdapter1Interface *adapterBluez5 = nullptr;
184     QTimer *discoveryTimer = nullptr;
185     QList<OrgFreedesktopDBusPropertiesInterface *> propertyMonitors;
186 
187     void deviceFoundBluez5(const QString &devicePath, const QVariantMap &properties);
188     void startBluez5(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods);
189 
190     bool useExtendedDiscovery;
191     QTimer extendedDiscoveryTimer;
192     QMap<QString, QVariantMap> devicesProperties;
193 #endif
194 
195 #ifdef QT_WIN_BLUETOOTH
196 public:
197     static QString discoveredLeDeviceSystemPath(const QBluetoothAddress &deviceAddress);
198 
199 private:
200     void cancelDiscovery();
201     void restartDiscovery();
202     void finishDiscovery(QBluetoothDeviceDiscoveryAgent::Error errorCode, const QString &errorText);
203 
204     void startLeDevicesDiscovery();
205     void completeLeDevicesDiscovery(const QVariant &res);
206     void startClassicDevicesDiscovery(Qt::HANDLE hSearch = nullptr);
207     void completeClassicDevicesDiscovery(const QVariant &res);
208 
209     void processDiscoveredDevice(const QBluetoothDeviceInfo &foundDevice);
210 
211     QBluetoothAddress adapterAddress;
212     bool pendingCancel;
213     bool pendingStart;
214     bool active;
215 
216     QThread *threadLE = nullptr;
217     QThread *threadClassic = nullptr;
218     ThreadWorkerDeviceDiscovery *threadWorkerLE = nullptr;
219     ThreadWorkerDeviceDiscovery *threadWorkerClassic = nullptr;
220 #endif
221 
222 #ifdef QT_WINRT_BLUETOOTH
223 private slots:
224     void registerDevice(const QBluetoothDeviceInfo &info);
225     void updateDeviceData(const QBluetoothAddress &address, QBluetoothDeviceInfo::Fields fields,
226                           qint16 rssi, ManufacturerData manufacturerData);
227     void onScanFinished();
228 
229 private:
230     void disconnectAndClearWorker();
231     QPointer<QWinRTBluetoothDeviceDiscoveryWorker> worker;
232     QTimer *leScanTimer;
233 #endif
234 
235 #ifdef Q_OS_DARWIN
236 
237     void startLE();
238 
239 #ifdef Q_OS_MACOS
240 
241     void startClassic();
242 
243     // Classic (IOBluetooth) inquiry delegate's methods:
244     void inquiryFinished() override;
245     void error(IOReturn error) override;
246     void classicDeviceFound(void *device) override;
247     // Classic (IOBluetooth) errors:
248     void setError(IOReturn error, const QString &text = QString());
249 
250 #endif // Q_OS_MACOS
251 
252     // LE scan delegates (CoreBluetooth, all Darwin OSes):
253     void LEinquiryFinished();
254     void LEinquiryError(QBluetoothDeviceDiscoveryAgent::Error error);
255     void LEnotSupported();
256 
257     // LE errors:
258     void setError(QBluetoothDeviceDiscoveryAgent::Error,
259                   const QString &text = QString());
260 
261     // Both LE and Classic devices go there:
262     void deviceFound(const QBluetoothDeviceInfo &newDeviceInfo);
263 
264     enum AgentState {
265         NonActive,
266         ClassicScan, // macOS (IOBluetooth) only
267         LEScan
268     } agentState;
269 
270     QBluetoothAddress adapterAddress;
271 
272     bool startPending;
273     bool stopPending;
274 
275 #ifdef Q_OS_MACOS
276 
277     DarwinBluetooth::ScopedPointer controller;
278     DarwinBluetooth::ScopedPointer inquiry;
279 
280 #endif // Q_OS_MACOS
281 
282     DarwinBluetooth::ScopedPointer inquiryLE;
283 
284 #endif // Q_OS_DARWIN
285 
286     int lowEnergySearchTimeout;
287     QBluetoothDeviceDiscoveryAgent::DiscoveryMethods requestedMethods;
288     QBluetoothDeviceDiscoveryAgent *q_ptr;
289 };
290 
291 QT_END_NAMESPACE
292 
293 #endif
294