1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#include "qbluetoothhostinfo.h"
4
5#include "qbluetoothdevicediscoveryagent.h"
6#include "qbluetoothdevicediscoveryagent_p.h"
7#include <QtCore/qloggingcategory.h>
8
9QT_BEGIN_NAMESPACE
10
11Q_DECLARE_LOGGING_CATEGORY(QT_BT)
12
13/*!
14 \class QBluetoothDeviceDiscoveryAgent
15 \inmodule QtBluetooth
16 \brief The QBluetoothDeviceDiscoveryAgent class discovers the Bluetooth
17 devices nearby.
18
19 \since 5.2
20
21 To discover the nearby Bluetooth devices:
22 \list
23 \li create an instance of QBluetoothDeviceDiscoveryAgent,
24 \li connect to either the deviceDiscovered() or finished() signals,
25 \li and call start().
26 \endlist
27
28 \snippet doc_src_qtbluetooth.cpp device_discovery
29
30 To retrieve results asynchronously, connect to the deviceDiscovered() signal. To get a list of
31 all discovered devices, call discoveredDevices() after the finished() signal.
32
33 This class can be used to discover Classic and Low Energy Bluetooth devices.
34 The individual device type can be determined via the
35 \l QBluetoothDeviceInfo::coreConfigurations() attribute.
36 In most cases the list returned by \l discoveredDevices() contains both types
37 of devices. However not every platform can detect both types of devices.
38 On platforms with this limitation (for example iOS only suports Low Energy discovery),
39 the discovery process will limit the search to the type which is supported.
40
41 \note Since Android 6.0 the ability to detect devices requires ACCESS_COARSE_LOCATION.
42
43 \note The Win32 backend currently does not support the Received Signal Strength
44 Indicator (RSSI), as well as the Manufacturer Specific Data, or other data
45 updates advertised by Bluetooth LE devices after discovery.
46*/
47
48/*!
49 \enum QBluetoothDeviceDiscoveryAgent::Error
50
51 Indicates all possible error conditions found during Bluetooth device discovery.
52
53 \value NoError No error has occurred.
54 \value PoweredOffError The Bluetooth adaptor is powered off, power it on before doing discovery.
55 \value InputOutputError Writing or reading from the device resulted in an error.
56 \value InvalidBluetoothAdapterError The passed local adapter address does not match the physical
57 adapter address of any local Bluetooth device.
58 \value [since 5.5] UnsupportedPlatformError Device discovery is not possible or implemented
59 on the current platform. The error is set in
60 response to a call to \l start(). An example for
61 such cases are iOS versions below 5.0 which do
62 not support Bluetooth device search at all.
63 \value [since 5.8] UnsupportedDiscoveryMethod One of the requested discovery methods is not
64 supported by the current platform.
65 \value [since 6.2] LocationServiceTurnedOffError The location service is turned off.
66 Usage of Bluetooth APIs is not possible
67 when location service is turned off.
68 \value [since 6.4] MissingPermissionsError The operating system requests
69 permissions which were not
70 granted by the user.
71 \value UnknownError An unknown error has occurred.
72*/
73
74/*!
75 \enum QBluetoothDeviceDiscoveryAgent::DiscoveryMethod
76
77 This enum descibes the type of discovery method employed by the QBluetoothDeviceDiscoveryAgent.
78
79 \value NoMethod The discovery is not possible. None of the available
80 methods are supported.
81 \value ClassicMethod The discovery process searches for Bluetooth Classic
82 (BaseRate) devices.
83 \value LowEnergyMethod The discovery process searches for Bluetooth Low Energy
84 devices.
85
86 \sa supportedDiscoveryMethods()
87 \since 5.8
88*/
89
90/*!
91 \fn void QBluetoothDeviceDiscoveryAgent::deviceDiscovered(const QBluetoothDeviceInfo &info)
92
93 This signal is emitted when the Bluetooth device described by \a info is discovered.
94
95 The signal is emitted as soon as the most important device information
96 has been collected. However, as long as the \l finished() signal has not
97 been emitted the information collection continues even for already discovered
98 devices. This is particularly true for signal strength information (RSSI) and
99 manufacturer data updates. If the use case requires continuous manufacturer data
100 or RSSI updates it is advisable to retrieve the device information via
101 \l discoveredDevices() once the discovery has finished or listen to the
102 \l deviceUpdated() signal.
103
104 If \l lowEnergyDiscoveryTimeout() is larger than 0 the signal is only ever
105 emitted when at least one attribute of \a info changes. This reflects the desire to
106 receive updates as more precise information becomes available. The exception to this
107 behavior is the case when \l lowEnergyDiscoveryTimeout is set to \c 0. A timeout of \c 0
108 expresses the desire to monitor the appearance and disappearance of Low Energy devices
109 over time. Under this condition the \l deviceDiscovered() signal is emitted even if
110 \a info has not changed since the last signal emission.
111
112 \sa QBluetoothDeviceInfo::rssi(), lowEnergyDiscoveryTimeout()
113*/
114
115/*!
116 \fn void QBluetoothDeviceDiscoveryAgent::deviceUpdated(const QBluetoothDeviceInfo &info, QBluetoothDeviceInfo::Fields updatedFields)
117
118 This signal is emitted when the agent receives additional information about
119 the Bluetooth device described by \a info. The \a updatedFields flags tell
120 which information has been updated.
121
122 During discovery, some information can change dynamically, such as
123 \l {QBluetoothDeviceInfo::rssi()}{signal strength} and
124 \l {QBluetoothDeviceInfo::manufacturerData()}{manufacturerData}.
125 This signal informs you that if your application is displaying this data, it
126 can be updated, rather than waiting until the discovery has finished.
127
128 \sa QBluetoothDeviceInfo::rssi(), lowEnergyDiscoveryTimeout()
129*/
130
131/*!
132 \fn void QBluetoothDeviceDiscoveryAgent::finished()
133
134 This signal is emitted when Bluetooth device discovery completes.
135 The signal is not going to be emitted if the device discovery finishes with an error.
136*/
137
138/*!
139 \fn void QBluetoothDeviceDiscoveryAgent::errorOccurred(QBluetoothDeviceDiscoveryAgent::Error
140 error)
141
142 This signal is emitted when an \a error occurs during Bluetooth device discovery.
143 The \a error parameter describes the error that occurred.
144
145 \sa error(), errorString()
146 \since 6.2
147*/
148
149/*!
150 \fn void QBluetoothDeviceDiscoveryAgent::canceled()
151
152 This signal is emitted when device discovery is aborted by a call to stop().
153*/
154
155/*!
156 \fn bool QBluetoothDeviceDiscoveryAgent::isActive() const
157
158 Returns true if the agent is currently discovering Bluetooth devices, otherwise returns false.
159*/
160
161/*!
162 Constructs a new Bluetooth device discovery agent with parent \a parent.
163*/
164QBluetoothDeviceDiscoveryAgent::QBluetoothDeviceDiscoveryAgent(QObject *parent) :
165 QObject(parent),
166 d_ptr(new QBluetoothDeviceDiscoveryAgentPrivate(QBluetoothAddress(), this))
167{
168}
169
170/*!
171 Constructs a new Bluetooth device discovery agent with \a parent.
172
173 It uses \a deviceAdapter for the device search. If \a deviceAdapter is default constructed the resulting
174 QBluetoothDeviceDiscoveryAgent object will use the local default Bluetooth adapter.
175
176 If a \a deviceAdapter is specified that is not a local adapter \l error() will be set to
177 \l InvalidBluetoothAdapterError. Therefore it is recommended to test the error flag immediately after
178 using this constructor.
179
180 \sa error()
181*/
182QBluetoothDeviceDiscoveryAgent::QBluetoothDeviceDiscoveryAgent(
183 const QBluetoothAddress &deviceAdapter, QObject *parent) :
184 QObject(parent),
185 d_ptr(new QBluetoothDeviceDiscoveryAgentPrivate(deviceAdapter, this))
186{
187 if (!deviceAdapter.isNull()) {
188 const QList<QBluetoothHostInfo> localDevices = QBluetoothLocalDevice::allDevices();
189 for (const QBluetoothHostInfo &hostInfo : localDevices) {
190 if (hostInfo.address() == deviceAdapter)
191 return;
192 }
193 d_ptr->lastError = InvalidBluetoothAdapterError;
194 d_ptr->errorString = tr(s: "Invalid Bluetooth adapter address");
195 }
196}
197
198/*!
199 Destructor for ~QBluetoothDeviceDiscoveryAgent()
200*/
201QBluetoothDeviceDiscoveryAgent::~QBluetoothDeviceDiscoveryAgent()
202{
203 delete d_ptr;
204}
205
206/*!
207 Returns a list of all discovered Bluetooth devices.
208*/
209QList<QBluetoothDeviceInfo> QBluetoothDeviceDiscoveryAgent::discoveredDevices() const
210{
211 Q_D(const QBluetoothDeviceDiscoveryAgent);
212 return d->discoveredDevices;
213}
214
215/*!
216 Sets the maximum search time for Bluetooth Low Energy device search to
217 \a timeout in milliseconds. If \a timeout is \c 0 the discovery runs
218 until \l stop() is called.
219
220 This reflects the fact that the discovery process for Bluetooth Low Energy devices
221 is mostly open ended. The platform continues to look for more devices until the search is
222 manually stopped. The timeout ensures that the search is aborted after \a timeout milliseconds.
223 Of course, it is still possible to manually abort the discovery by calling \l stop().
224
225 The new timeout value does not take effect until the device search is restarted.
226 In addition the timeout does not affect the classic Bluetooth device search. Depending on
227 the platform the classic search may add more time to the total discovery process
228 beyond \a timeout.
229
230 For a reliable Bluetooth Low Energy discovery, use at least 40000 milliseconds.
231
232 \sa lowEnergyDiscoveryTimeout()
233 \since 5.8
234 */
235void QBluetoothDeviceDiscoveryAgent::setLowEnergyDiscoveryTimeout(int timeout)
236{
237 Q_D(QBluetoothDeviceDiscoveryAgent);
238
239 // cannot deliberately turn it off
240 if (timeout < 0) {
241 qCDebug(QT_BT) << "The Bluetooth Low Energy device discovery timeout cannot be negative.";
242 return;
243 }
244
245 if (d->lowEnergySearchTimeout < 0) {
246 qCDebug(QT_BT) << "The Bluetooth Low Energy device discovery timeout cannot be "
247 "set on a backend which does not support this feature.";
248 return;
249 }
250
251 d->lowEnergySearchTimeout = timeout;
252}
253
254/*!
255 Returns a timeout in milliseconds that is applied to the Bluetooth Low Energy device search.
256 A value of \c -1 implies that the platform does not support this property and the timeout for
257 the device search cannot be adjusted. A return value of \c 0
258 implies a never-ending search which must be manually stopped via \l stop().
259
260 \sa setLowEnergyDiscoveryTimeout()
261 \since 5.8
262 */
263int QBluetoothDeviceDiscoveryAgent::lowEnergyDiscoveryTimeout() const
264{
265 Q_D(const QBluetoothDeviceDiscoveryAgent);
266 return d->lowEnergySearchTimeout;
267}
268
269/*!
270 \fn QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods()
271
272 This function returns the discovery methods supported by the current platform.
273 It can be used to limit the scope of the device discovery.
274
275 \since 5.8
276*/
277
278/*!
279 Starts Bluetooth device discovery, if it is not already started.
280
281 The deviceDiscovered() signal is emitted as each device is discovered. The finished() signal
282 is emitted once device discovery is complete. The discovery utilizes the maximum set of
283 supported discovery methods on the platform.
284
285 \sa supportedDiscoveryMethods()
286*/
287void QBluetoothDeviceDiscoveryAgent::start()
288{
289 Q_D(QBluetoothDeviceDiscoveryAgent);
290 if (!isActive())
291 d->start(methods: supportedDiscoveryMethods());
292}
293
294/*!
295 Starts Bluetooth device discovery, if it is not already started and the provided
296 \a methods are supported.
297 The discovery \a methods limit the scope of the device search.
298 For example, if the target service or device is a Bluetooth Low Energy device,
299 this function could be used to limit the search to Bluetooth Low Energy devices and
300 thereby reduces the discovery time significantly.
301
302 \note \a methods only determines the type of discovery and does not imply
303 the filtering of the results. For example, the search may still contain classic bluetooth devices
304 despite \a methods being set to \l {QBluetoothDeviceDiscoveryAgent::LowEnergyMethod}
305 {LowEnergyMethod} only. This may happen due to previously cached search results
306 which may be incorporated into the search results.
307
308 \since 5.8
309*/
310void QBluetoothDeviceDiscoveryAgent::start(DiscoveryMethods methods)
311{
312 if (methods == NoMethod)
313 return;
314
315 DiscoveryMethods supported =
316 QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods();
317
318 Q_D(QBluetoothDeviceDiscoveryAgent);
319 if (!((supported & methods) == methods)) {
320 d->lastError = UnsupportedDiscoveryMethod;
321 d->errorString = QBluetoothDeviceDiscoveryAgent::tr(s: "One or more device discovery methods "
322 "are not supported on this platform");
323 emit errorOccurred(error: d->lastError);
324 return;
325 }
326
327 if (!isActive())
328 d->start(methods);
329}
330
331/*!
332 Stops Bluetooth device discovery. The cancel() signal is emitted once the
333 device discovery is canceled. start() maybe called before the cancel signal is
334 received. Once start() has been called the cancel signal from the prior
335 discovery will be discarded.
336*/
337void QBluetoothDeviceDiscoveryAgent::stop()
338{
339 Q_D(QBluetoothDeviceDiscoveryAgent);
340 if (isActive() && d->lastError != InvalidBluetoothAdapterError)
341 d->stop();
342}
343
344bool QBluetoothDeviceDiscoveryAgent::isActive() const
345{
346 Q_D(const QBluetoothDeviceDiscoveryAgent);
347 return d->isActive();
348}
349
350/*!
351 Returns the last error.
352
353 Any possible previous errors are cleared upon restarting the discovery.
354*/
355QBluetoothDeviceDiscoveryAgent::Error QBluetoothDeviceDiscoveryAgent::error() const
356{
357 Q_D(const QBluetoothDeviceDiscoveryAgent);
358
359 return d->lastError;
360}
361
362/*!
363 Returns a human-readable description of the last error.
364
365 \sa error(), errorOccurred()
366*/
367QString QBluetoothDeviceDiscoveryAgent::errorString() const
368{
369 Q_D(const QBluetoothDeviceDiscoveryAgent);
370 return d->errorString;
371}
372
373QT_END_NAMESPACE
374
375#include "moc_qbluetoothdevicediscoveryagent.cpp"
376

source code of qtconnectivity/src/bluetooth/qbluetoothdevicediscoveryagent.cpp