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