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

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