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 | |
4 | #include "qbluetoothhostinfo.h" |
5 | #include "qbluetoothlocaldevice.h" |
6 | #include "qbluetoothservicediscoveryagent.h" |
7 | #include "qbluetoothservicediscoveryagent_p.h" |
8 | |
9 | #include "qbluetoothdevicediscoveryagent.h" |
10 | |
11 | QT_BEGIN_NAMESPACE |
12 | |
13 | /*! |
14 | \class QBluetoothServiceDiscoveryAgent |
15 | \inmodule QtBluetooth |
16 | \brief The QBluetoothServiceDiscoveryAgent class enables you to query for |
17 | Bluetooth services. |
18 | |
19 | \since 5.2 |
20 | |
21 | The discovery process relies on the Bluetooth Service Discovery Process (SDP). |
22 | The following steps are required to query the services provided by all contactable |
23 | Bluetooth devices: |
24 | |
25 | \list |
26 | \li create an instance of QBluetoothServiceDiscoveryAgent, |
27 | \li connect to either the serviceDiscovered() or finished() signals, |
28 | \li and call start(). |
29 | \endlist |
30 | |
31 | \snippet doc_src_qtbluetooth.cpp service_discovery |
32 | |
33 | By default a minimal service discovery is performed. In this mode, the returned \l QBluetoothServiceInfo |
34 | objects are guaranteed to contain only device and service UUID information. Depending |
35 | on platform and device capabilities, other service information may also be available. |
36 | The minimal service discovery mode relies on cached SDP data of the platform. Therefore it |
37 | is possible that this discovery does not find a device although it is physically available. |
38 | In such cases a full discovery must be performed to force an update of the platform cache. |
39 | However for most use cases a minimal discovery is adequate as it is much quicker and other |
40 | classes which require up-to-date information such as QBluetoothSocket::connectToService() |
41 | will perform additional discovery if required. If the full service information is required, |
42 | pass \l FullDiscovery as the discoveryMode parameter to start(). |
43 | |
44 | This class may internally utilize \l QBluetoothDeviceDiscoveryAgent to find unknown devices. |
45 | |
46 | The service discovery may find Bluetooth Low Energy services too if the target device |
47 | is a combination of a classic and Low Energy device. Those devices are required to advertise |
48 | their Low Energy services via SDP. If the target device only supports Bluetooth Low |
49 | Energy services, it is likely to not advertise them via SDP. The \l QLowEnergyController class |
50 | should be utilized to perform the service discovery on Low Energy devices. |
51 | |
52 | On iOS, this class cannot be used because the platform does not expose |
53 | an API which may permit access to QBluetoothServiceDiscoveryAgent related features. |
54 | |
55 | \sa QBluetoothDeviceDiscoveryAgent, QLowEnergyController |
56 | */ |
57 | |
58 | /*! |
59 | \enum QBluetoothServiceDiscoveryAgent::Error |
60 | |
61 | This enum describes errors that can occur during service discovery. |
62 | |
63 | \value NoError No error has occurred. |
64 | \value PoweredOffError The Bluetooth adaptor is powered off, power it on before doing discovery. |
65 | \value InputOutputError Writing or reading from the device resulted in an error. |
66 | \value [since 5.3] InvalidBluetoothAdapterError The passed local adapter address does not |
67 | match the physical adapter address of any |
68 | local Bluetooth device. |
69 | \value [since 6.4] MissingPermissionsError The operating system requests |
70 | permissions which were not |
71 | granted by the user. |
72 | \value UnknownError An unknown error has occurred. |
73 | */ |
74 | |
75 | /*! |
76 | \enum QBluetoothServiceDiscoveryAgent::DiscoveryMode |
77 | |
78 | This enum describes the service discovery mode. |
79 | |
80 | \value MinimalDiscovery Performs a minimal service discovery. The QBluetoothServiceInfo |
81 | objects returned may be incomplete and are only guaranteed to contain device and service UUID information. |
82 | Since a minimal discovery relies on cached SDP data it may not find a physically existing |
83 | device until a \c FullDiscovery is performed. |
84 | \value FullDiscovery Performs a full service discovery. |
85 | */ |
86 | |
87 | /*! |
88 | \fn QBluetoothServiceDiscoveryAgent::serviceDiscovered(const QBluetoothServiceInfo &info) |
89 | |
90 | This signal is emitted when the Bluetooth service described by \a info is discovered. |
91 | |
92 | \note The passed \l QBluetoothServiceInfo parameter may contain a Bluetooth Low Energy |
93 | service if the target device advertises the service via SDP. This is required from device |
94 | which support both, classic Bluetooth (BaseRate) and Low Energy services. |
95 | |
96 | \sa QBluetoothDeviceInfo::coreConfigurations() |
97 | */ |
98 | |
99 | /*! |
100 | \fn QBluetoothServiceDiscoveryAgent::finished() |
101 | |
102 | This signal is emitted when the Bluetooth service discovery completes. |
103 | |
104 | Unlike the \l QBluetoothDeviceDiscoveryAgent::finished() signal this |
105 | signal will even be emitted when an error occurred during the service discovery. Therefore |
106 | it is recommended to check the \l errorOccurred() signal to evaluate the success of the |
107 | service discovery discovery. |
108 | */ |
109 | |
110 | /*! |
111 | \fn void QBluetoothServiceDiscoveryAgent::errorOccurred(QBluetoothServiceDiscoveryAgent::Error |
112 | error) |
113 | |
114 | This signal is emitted when an \a error occurs. The \a error parameter describes the error that |
115 | occurred. |
116 | |
117 | \since 6.2 |
118 | */ |
119 | |
120 | /*! |
121 | Constructs a new QBluetoothServiceDiscoveryAgent with \a parent. The search is performed via the |
122 | local default Bluetooth adapter. |
123 | */ |
124 | QBluetoothServiceDiscoveryAgent::QBluetoothServiceDiscoveryAgent(QObject *parent) |
125 | : QObject(parent), |
126 | d_ptr(new QBluetoothServiceDiscoveryAgentPrivate(this, QBluetoothAddress())) |
127 | { |
128 | } |
129 | |
130 | /*! |
131 | Constructs a new QBluetoothServiceDiscoveryAgent for \a deviceAdapter and with \a parent. |
132 | |
133 | It uses \a deviceAdapter for the service search. If \a deviceAdapter is default constructed |
134 | the resulting QBluetoothServiceDiscoveryAgent object will use the local default Bluetooth adapter. |
135 | |
136 | If a \a deviceAdapter is specified that is not a local adapter \l error() will be set to |
137 | \l InvalidBluetoothAdapterError. Therefore it is recommended to test the error flag immediately after |
138 | using this constructor. |
139 | |
140 | \note On WinRT the passed adapter address will be ignored. |
141 | |
142 | \note On Android passing any \a deviceAdapter address is meaningless as Android 6.0 or later does not publish |
143 | the local Bluetooth address anymore. Subsequently, the passed adapter address can never be matched |
144 | against the local adapter address. Therefore the subsequent call to \l start() will always trigger |
145 | \l InvalidBluetoothAdapterError. |
146 | |
147 | \sa error() |
148 | */ |
149 | QBluetoothServiceDiscoveryAgent::QBluetoothServiceDiscoveryAgent(const QBluetoothAddress &deviceAdapter, QObject *parent) |
150 | : QObject(parent), |
151 | d_ptr(new QBluetoothServiceDiscoveryAgentPrivate(this, deviceAdapter)) |
152 | { |
153 | if (!deviceAdapter.isNull()) { |
154 | const QList<QBluetoothHostInfo> localDevices = QBluetoothLocalDevice::allDevices(); |
155 | for (const QBluetoothHostInfo &hostInfo : localDevices) { |
156 | if (hostInfo.address() == deviceAdapter) |
157 | return; |
158 | } |
159 | d_ptr->error = InvalidBluetoothAdapterError; |
160 | d_ptr->errorString = tr(s: "Invalid Bluetooth adapter address"); |
161 | } |
162 | } |
163 | |
164 | /*! |
165 | |
166 | Destructor for QBluetoothServiceDiscoveryAgent |
167 | |
168 | */ |
169 | |
170 | QBluetoothServiceDiscoveryAgent::~QBluetoothServiceDiscoveryAgent() |
171 | { |
172 | if (isActive()) { |
173 | disconnect(); //don't emit any signals due to stop() |
174 | stop(); |
175 | } |
176 | |
177 | delete d_ptr; |
178 | } |
179 | |
180 | /*! |
181 | Returns the list of all discovered services. |
182 | |
183 | This list of services accumulates newly discovered services from multiple calls |
184 | to \l start(). Unless \l clear() is called the list cannot decrease in size. This implies |
185 | that if a remote Bluetooth device moves out of range in between two subsequent calls |
186 | to \l start() the list may contain stale entries. |
187 | |
188 | \note The list of services should always be cleared before the discovery mode is changed. |
189 | |
190 | \sa clear() |
191 | */ |
192 | QList<QBluetoothServiceInfo> QBluetoothServiceDiscoveryAgent::discoveredServices() const |
193 | { |
194 | Q_D(const QBluetoothServiceDiscoveryAgent); |
195 | |
196 | return d->discoveredServices; |
197 | } |
198 | /*! |
199 | Sets the UUID filter to \a uuids. Only services matching the UUIDs in \a uuids will be |
200 | returned. The matching applies to the service's |
201 | \l {QBluetoothServiceInfo::ServiceId}{ServiceId} and \l {QBluetoothServiceInfo::ServiceClassIds} {ServiceClassIds} |
202 | attributes. |
203 | |
204 | An empty UUID list is equivalent to a list containing only QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup. |
205 | |
206 | \sa uuidFilter() |
207 | */ |
208 | void QBluetoothServiceDiscoveryAgent::setUuidFilter(const QList<QBluetoothUuid> &uuids) |
209 | { |
210 | Q_D(QBluetoothServiceDiscoveryAgent); |
211 | |
212 | d->uuidFilter = uuids; |
213 | } |
214 | |
215 | /*! |
216 | This is an overloaded member function, provided for convenience. |
217 | |
218 | Sets the UUID filter to a list containing the single element \a uuid. |
219 | The matching applies to the service's \l {QBluetoothServiceInfo::ServiceId}{ServiceId} |
220 | and \l {QBluetoothServiceInfo::ServiceClassIds} {ServiceClassIds} |
221 | attributes. |
222 | |
223 | \sa uuidFilter() |
224 | */ |
225 | void QBluetoothServiceDiscoveryAgent::setUuidFilter(const QBluetoothUuid &uuid) |
226 | { |
227 | Q_D(QBluetoothServiceDiscoveryAgent); |
228 | |
229 | d->uuidFilter.clear(); |
230 | d->uuidFilter.append(t: uuid); |
231 | } |
232 | |
233 | /*! |
234 | Returns the UUID filter. |
235 | |
236 | \sa setUuidFilter() |
237 | */ |
238 | QList<QBluetoothUuid> QBluetoothServiceDiscoveryAgent::uuidFilter() const |
239 | { |
240 | Q_D(const QBluetoothServiceDiscoveryAgent); |
241 | |
242 | return d->uuidFilter; |
243 | } |
244 | |
245 | /*! |
246 | Sets the remote device address to \a address. If \a address is default constructed, |
247 | services will be discovered on all contactable Bluetooth devices. A new remote |
248 | address can only be set while there is no service discovery in progress; otherwise |
249 | this function returns false. |
250 | |
251 | On some platforms the service discovery might lead to pairing requests. |
252 | Therefore it is not recommended to do service discoveries on all devices. |
253 | This function can be used to restrict the service discovery to a particular device. |
254 | |
255 | \sa remoteAddress() |
256 | */ |
257 | bool QBluetoothServiceDiscoveryAgent::setRemoteAddress(const QBluetoothAddress &address) |
258 | { |
259 | if (isActive()) |
260 | return false; |
261 | if (!address.isNull()) |
262 | d_ptr->singleDevice = true; |
263 | d_ptr->deviceAddress = address; |
264 | return true; |
265 | } |
266 | |
267 | /*! |
268 | Returns the remote device address. If \l setRemoteAddress() is not called, the function |
269 | will return a default constructed \l QBluetoothAddress. |
270 | |
271 | \sa setRemoteAddress() |
272 | */ |
273 | QBluetoothAddress QBluetoothServiceDiscoveryAgent::remoteAddress() const |
274 | { |
275 | if (d_ptr->singleDevice == true) |
276 | return d_ptr->deviceAddress; |
277 | else |
278 | return QBluetoothAddress(); |
279 | } |
280 | |
281 | namespace DarwinBluetooth { |
282 | |
283 | void qt_test_iobluetooth_runloop(); |
284 | |
285 | } |
286 | |
287 | |
288 | /*! |
289 | Starts service discovery. \a mode specifies the type of service discovery to perform. |
290 | |
291 | On some platforms, device discovery may lead to pairing requests. |
292 | |
293 | \sa DiscoveryMode |
294 | */ |
295 | void QBluetoothServiceDiscoveryAgent::start(DiscoveryMode mode) |
296 | { |
297 | Q_D(QBluetoothServiceDiscoveryAgent); |
298 | #ifdef QT_OSX_BLUETOOTH |
299 | // Make sure we are on the right thread/have a run loop: |
300 | DarwinBluetooth::qt_test_iobluetooth_runloop(); |
301 | #endif |
302 | |
303 | if (d->discoveryState() == QBluetoothServiceDiscoveryAgentPrivate::Inactive |
304 | && d->error != InvalidBluetoothAdapterError) { |
305 | #if QT_CONFIG(bluez) |
306 | // done to avoid repeated parsing for adapter address |
307 | // on Bluez5 |
308 | d->foundHostAdapterPath.clear(); |
309 | #endif |
310 | d->setDiscoveryMode(mode); |
311 | // Clear any possible previous errors |
312 | d->error = QBluetoothServiceDiscoveryAgent::NoError; |
313 | d->errorString.clear(); |
314 | if (d->deviceAddress.isNull()) { |
315 | d->startDeviceDiscovery(); |
316 | } else { |
317 | d->discoveredDevices << QBluetoothDeviceInfo(d->deviceAddress, QString(), 0); |
318 | d->startServiceDiscovery(); |
319 | } |
320 | } |
321 | } |
322 | |
323 | /*! |
324 | Stops the service discovery process. The \l canceled() signal will be emitted once |
325 | the search has stopped. |
326 | */ |
327 | void QBluetoothServiceDiscoveryAgent::stop() |
328 | { |
329 | Q_D(QBluetoothServiceDiscoveryAgent); |
330 | |
331 | if (d->error == InvalidBluetoothAdapterError || !isActive()) |
332 | return; |
333 | |
334 | switch (d->discoveryState()) { |
335 | case QBluetoothServiceDiscoveryAgentPrivate::DeviceDiscovery: |
336 | d->stopDeviceDiscovery(); |
337 | break; |
338 | case QBluetoothServiceDiscoveryAgentPrivate::ServiceDiscovery: |
339 | d->stopServiceDiscovery(); |
340 | break; |
341 | default: |
342 | break; |
343 | } |
344 | |
345 | d->discoveredDevices.clear(); |
346 | } |
347 | |
348 | /*! |
349 | Clears the results of previous service discoveries and resets \l uuidFilter(). |
350 | This function does nothing during an ongoing service discovery (see \l isActive()). |
351 | |
352 | \sa discoveredServices() |
353 | */ |
354 | void QBluetoothServiceDiscoveryAgent::clear() |
355 | { |
356 | Q_D(QBluetoothServiceDiscoveryAgent); |
357 | |
358 | //don't clear the list while the search is ongoing |
359 | if (isActive()) |
360 | return; |
361 | |
362 | d->discoveredDevices.clear(); |
363 | d->discoveredServices.clear(); |
364 | d->uuidFilter.clear(); |
365 | } |
366 | |
367 | /*! |
368 | Returns \c true if the service discovery is currently active; otherwise returns \c false. |
369 | An active discovery can be stopped by calling \l stop(). |
370 | */ |
371 | bool QBluetoothServiceDiscoveryAgent::isActive() const |
372 | { |
373 | Q_D(const QBluetoothServiceDiscoveryAgent); |
374 | |
375 | return d->state != QBluetoothServiceDiscoveryAgentPrivate::Inactive; |
376 | } |
377 | |
378 | /*! |
379 | Returns the type of error that last occurred. If the service discovery is done |
380 | for a single \l remoteAddress() it will return errors that occurred while trying to discover |
381 | services on that device. If the \l remoteAddress() is not set and devices are |
382 | discovered by a scan, errors during service discovery on individual |
383 | devices are not saved and no signals are emitted. In this case, errors are |
384 | fairly normal as some devices may not respond to discovery or |
385 | may no longer be in range. Such errors are suppressed. If no services |
386 | are returned, it can be assumed no services could be discovered. |
387 | |
388 | Any possible previous errors are cleared upon restarting the discovery. |
389 | */ |
390 | QBluetoothServiceDiscoveryAgent::Error QBluetoothServiceDiscoveryAgent::error() const |
391 | { |
392 | Q_D(const QBluetoothServiceDiscoveryAgent); |
393 | |
394 | return d->error; |
395 | } |
396 | |
397 | /*! |
398 | Returns a human-readable description of the last error that occurred during the |
399 | service discovery. |
400 | |
401 | \sa error(), errorOccurred() |
402 | */ |
403 | QString QBluetoothServiceDiscoveryAgent::errorString() const |
404 | { |
405 | Q_D(const QBluetoothServiceDiscoveryAgent); |
406 | return d->errorString; |
407 | } |
408 | |
409 | |
410 | /*! |
411 | \fn QBluetoothServiceDiscoveryAgent::canceled() |
412 | |
413 | This signal is triggered when the service discovery was canceled via a call to \l stop(). |
414 | */ |
415 | |
416 | |
417 | /*! |
418 | Starts device discovery. |
419 | */ |
420 | void QBluetoothServiceDiscoveryAgentPrivate::startDeviceDiscovery() |
421 | { |
422 | Q_Q(QBluetoothServiceDiscoveryAgent); |
423 | |
424 | if (!deviceDiscoveryAgent) { |
425 | #if QT_CONFIG(bluez) |
426 | deviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(m_deviceAdapterAddress, q); |
427 | #else |
428 | deviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(q); |
429 | #endif |
430 | QObject::connect(sender: deviceDiscoveryAgent, signal: &QBluetoothDeviceDiscoveryAgent::finished, |
431 | context: q, slot: [this](){ |
432 | this->_q_deviceDiscoveryFinished(); |
433 | }); |
434 | QObject::connect(sender: deviceDiscoveryAgent, signal: &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, |
435 | context: q, slot: [this](const QBluetoothDeviceInfo &info){ |
436 | this->_q_deviceDiscovered(info); |
437 | }); |
438 | QObject::connect(sender: deviceDiscoveryAgent, signal: &QBluetoothDeviceDiscoveryAgent::errorOccurred, context: q, |
439 | slot: [this](QBluetoothDeviceDiscoveryAgent::Error newError) { |
440 | this->_q_deviceDiscoveryError(newError); |
441 | }); |
442 | } |
443 | |
444 | setDiscoveryState(DeviceDiscovery); |
445 | |
446 | deviceDiscoveryAgent->start(method: QBluetoothDeviceDiscoveryAgent::ClassicMethod); |
447 | } |
448 | |
449 | /*! |
450 | Stops device discovery. |
451 | */ |
452 | void QBluetoothServiceDiscoveryAgentPrivate::stopDeviceDiscovery() |
453 | { |
454 | // disconnect to avoid recursion during stop() - QTBUG-60131 |
455 | // we don't care about a potential signals from device discovery agent anymore |
456 | deviceDiscoveryAgent->disconnect(); |
457 | |
458 | deviceDiscoveryAgent->stop(); |
459 | delete deviceDiscoveryAgent; |
460 | deviceDiscoveryAgent = nullptr; |
461 | |
462 | setDiscoveryState(Inactive); |
463 | |
464 | Q_Q(QBluetoothServiceDiscoveryAgent); |
465 | emit q->canceled(); |
466 | } |
467 | |
468 | /*! |
469 | Called when device discovery finishes. |
470 | */ |
471 | void QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscoveryFinished() |
472 | { |
473 | if (deviceDiscoveryAgent->error() != QBluetoothDeviceDiscoveryAgent::NoError) { |
474 | //Forward the device discovery error |
475 | error = static_cast<QBluetoothServiceDiscoveryAgent::Error>(deviceDiscoveryAgent->error()); |
476 | errorString = deviceDiscoveryAgent->errorString(); |
477 | setDiscoveryState(Inactive); |
478 | Q_Q(QBluetoothServiceDiscoveryAgent); |
479 | emit q->errorOccurred(error); |
480 | emit q->finished(); |
481 | return; |
482 | } |
483 | |
484 | delete deviceDiscoveryAgent; |
485 | deviceDiscoveryAgent = nullptr; |
486 | |
487 | startServiceDiscovery(); |
488 | } |
489 | |
490 | void QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscovered(const QBluetoothDeviceInfo &info) |
491 | { |
492 | // look for duplicates, and cached entries |
493 | const auto addressEquals = [](const auto &a) { |
494 | return [a](const auto &info) { return info.address() == a; }; |
495 | }; |
496 | erase_if(list&: discoveredDevices, pred: addressEquals(info.address())); |
497 | discoveredDevices.prepend(t: info); |
498 | } |
499 | |
500 | void QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscoveryError(QBluetoothDeviceDiscoveryAgent::Error newError) |
501 | { |
502 | error = static_cast<QBluetoothServiceDiscoveryAgent::Error>(newError); |
503 | errorString = deviceDiscoveryAgent->errorString(); |
504 | |
505 | // disconnect to avoid recursion during stop() - QTBUG-60131 |
506 | // we don't care about a potential signals from device discovery agent anymore |
507 | deviceDiscoveryAgent->disconnect(); |
508 | |
509 | deviceDiscoveryAgent->stop(); |
510 | delete deviceDiscoveryAgent; |
511 | deviceDiscoveryAgent = nullptr; |
512 | |
513 | setDiscoveryState(Inactive); |
514 | Q_Q(QBluetoothServiceDiscoveryAgent); |
515 | emit q->errorOccurred(error); |
516 | emit q->finished(); |
517 | } |
518 | |
519 | /*! |
520 | Starts service discovery for the next device. |
521 | */ |
522 | void QBluetoothServiceDiscoveryAgentPrivate::startServiceDiscovery() |
523 | { |
524 | Q_Q(QBluetoothServiceDiscoveryAgent); |
525 | |
526 | if (discoveredDevices.isEmpty()) { |
527 | setDiscoveryState(Inactive); |
528 | emit q->finished(); |
529 | return; |
530 | } |
531 | |
532 | setDiscoveryState(ServiceDiscovery); |
533 | start(address: discoveredDevices.at(i: 0).address()); |
534 | } |
535 | |
536 | /*! |
537 | Stops service discovery. |
538 | */ |
539 | void QBluetoothServiceDiscoveryAgentPrivate::stopServiceDiscovery() |
540 | { |
541 | stop(); |
542 | |
543 | setDiscoveryState(Inactive); |
544 | } |
545 | |
546 | void QBluetoothServiceDiscoveryAgentPrivate::_q_serviceDiscoveryFinished() |
547 | { |
548 | if(!discoveredDevices.isEmpty()) { |
549 | discoveredDevices.removeFirst(); |
550 | } |
551 | |
552 | startServiceDiscovery(); |
553 | } |
554 | |
555 | bool QBluetoothServiceDiscoveryAgentPrivate::isDuplicatedService( |
556 | const QBluetoothServiceInfo &serviceInfo) const |
557 | { |
558 | //check the service is not already part of our known list |
559 | for (const QBluetoothServiceInfo &info : discoveredServices) { |
560 | if (info.device() == serviceInfo.device() |
561 | && info.serviceClassUuids() == serviceInfo.serviceClassUuids() |
562 | && info.serviceUuid() == serviceInfo.serviceUuid() |
563 | && info.serverChannel() == serviceInfo.serverChannel()) { |
564 | return true; |
565 | } |
566 | } |
567 | return false; |
568 | } |
569 | |
570 | QT_END_NAMESPACE |
571 | |
572 | #include "moc_qbluetoothservicediscoveryagent.cpp" |
573 |
Definitions
- QBluetoothServiceDiscoveryAgent
- QBluetoothServiceDiscoveryAgent
- ~QBluetoothServiceDiscoveryAgent
- discoveredServices
- setUuidFilter
- setUuidFilter
- uuidFilter
- setRemoteAddress
- remoteAddress
- start
- stop
- clear
- isActive
- error
- errorString
- startDeviceDiscovery
- stopDeviceDiscovery
- _q_deviceDiscoveryFinished
- _q_deviceDiscovered
- _q_deviceDiscoveryError
- startServiceDiscovery
- stopServiceDiscovery
- _q_serviceDiscoveryFinished
Learn Advanced QML with KDAB
Find out more