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 "qbluetoothserviceinfo.h"
5#include "qbluetoothserviceinfo_p.h"
6
7#include <QUrl>
8
9QT_BEGIN_NAMESPACE
10
11QT_IMPL_METATYPE_EXTERN(QBluetoothServiceInfo)
12QT_IMPL_METATYPE_EXTERN_TAGGED(QBluetoothServiceInfo::Sequence, QBluetoothServiceInfo__Sequence)
13QT_IMPL_METATYPE_EXTERN_TAGGED(QBluetoothServiceInfo::Alternative,
14 QBluetoothServiceInfo__Alternative)
15
16/*!
17 \class QBluetoothServiceInfo::Sequence
18 \inmodule QtBluetooth
19 \brief The Sequence class stores attributes of a Bluetooth Data Element
20 Sequence.
21
22 \since 5.2
23
24*/
25
26/*!
27 \fn QBluetoothServiceInfo::Sequence::Sequence()
28
29 Constructs a new empty sequence.
30*/
31
32/*!
33 \fn QBluetoothServiceInfo::Sequence::Sequence(const QList<QVariant> &list)
34
35 Constructs a new sequence that is a copy of \a list.
36*/
37
38/*!
39 \class QBluetoothServiceInfo::Alternative
40 \inmodule QtBluetooth
41 \brief The Alternative class stores attributes of a Bluetooth Data Element
42 Alternative.
43
44 \since 5.2
45*/
46
47/*!
48 \fn QBluetoothServiceInfo::Alternative::Alternative()
49
50 Constructs a new empty alternative.
51*/
52
53/*!
54 \fn QBluetoothServiceInfo::Alternative::Alternative(const QList<QVariant> &list)
55
56 Constructs a new alternative that is a copy of \a list.
57*/
58
59/*!
60 \class QBluetoothServiceInfo
61 \inmodule QtBluetooth
62 \brief The QBluetoothServiceInfo class enables access to the attributes of a
63 Bluetooth service.
64
65 \since 5.2
66
67 QBluetoothServiceInfo provides information about a service offered by a Bluetooth device.
68 In addition it can be used to register new services on the local device. Note that such
69 a registration only affects the Bluetooth SDP entries. Any server listening
70 for incoming connections (e.g an RFCOMM server) must be started before registerService()
71 is called. Deregistration must happen in the reverse order.
72
73 QBluetoothServiceInfo is not a value type in the traditional sense. All copies of the same
74 service info object share the same data as they do not detach upon changing them. This
75 ensures that two copies can (de)register the same Bluetooth service.
76
77 On iOS, this class cannot be used because the platform does not expose
78 an API which may permit access to QBluetoothServiceInfo related features.
79*/
80
81/*!
82 \enum QBluetoothServiceInfo::AttributeId
83
84 Bluetooth service attributes. Please check the Bluetooth Core Specification for a more detailed description of these attributes.
85
86 \value ServiceRecordHandle Specifies a service record from which attributes can be retrieved.
87 \value ServiceClassIds UUIDs of service classes that the service conforms to. The
88 most common service classes are defined in (\l QBluetoothUuid::ServiceClassUuid)
89 \value ServiceRecordState Attibute changes when any other service attribute is added, deleted or modified.
90 \value ServiceId UUID that uniquely identifies the service.
91 \value ProtocolDescriptorList List of protocols used by the service. The most common protocol Uuids are defined
92 in \l QBluetoothUuid::ProtocolUuid
93 \value BrowseGroupList List of browse groups the service is in.
94 \value LanguageBaseAttributeIdList List of language base attribute IDs to support human-readable attributes.
95 \value ServiceInfoTimeToLive Number of seconds for which the service record is expected to remain valid and unchanged.
96 \value ServiceAvailability Value indicating the availability of the service.
97 \value BluetoothProfileDescriptorList List of profiles to which the service conforms.
98 \value DocumentationUrl URL that points to the documentation on the service..
99 \value ClientExecutableUrl URL that refers to the location of an application that can be used to utilize the service.
100 \value IconUrl URL to the location of the icon representing the service.
101 \value AdditionalProtocolDescriptorList Additional protocols used by the service. This attribute extends \c ProtocolDescriptorList.
102 \value PrimaryLanguageBase Base index for primary language text descriptors.
103 \value ServiceName Name of the Bluetooth service in the primary language.
104 \value ServiceDescription Description of the Bluetooth service in the primary language.
105 \value ServiceProvider Name of the company / entity that provides the Bluetooth service primary language.
106
107 \note On Windows ServiceClassIds and ProtocolDescriptorList are automatically set to default
108 values when a service is created. Manually setting values for these attributes will not work and
109 might lead to unexpected results on this platform.
110*/
111
112/*!
113 \enum QBluetoothServiceInfo::Protocol
114
115 This enum describes the socket protocol used by the service.
116
117 \value UnknownProtocol The service uses an unknown socket protocol.
118 \value L2capProtocol The service uses the L2CAP socket protocol. This protocol is not supported
119 for direct socket connections on Android.
120 \value RfcommProtocol The service uses the RFCOMM socket protocol.
121*/
122
123/*!
124 \fn bool QBluetoothServiceInfo::isRegistered() const
125
126 Returns true if the service information is registered with the platform's Service Discovery Protocol
127 (SDP) implementation, otherwise returns false.
128*/
129
130bool QBluetoothServiceInfo::isRegistered() const
131{
132 return d_ptr->isRegistered();
133}
134
135/*!
136 \fn bool QBluetoothServiceInfo::registerService(const QBluetoothAddress &localAdapter)
137
138 Registers this service with the platform's Service Discovery Protocol (SDP) implementation,
139 making it findable by other devices when they perform service discovery. Returns true if the
140 service is successfully registered, otherwise returns false. Once registered changes to the record
141 cannot be made. The service must be unregistered and registered again with the changes.
142
143 The \a localAdapter parameter determines the local Bluetooth adapter under which
144 the service should be registered. If \a localAdapter is \c null the default Bluetooth adapter
145 will be used. If this service info object is already registered via a local adapter
146 and this is function is called using a different local adapter, the previous registration
147 is removed and the service reregistered using the new adapter.
148*/
149
150bool QBluetoothServiceInfo::registerService(const QBluetoothAddress &localAdapter)
151{
152#ifdef QT_OSX_BLUETOOTH
153 Q_UNUSED(localAdapter);
154 return d_ptr->registerService(*this);
155#else
156 return d_ptr->registerService(localAdapter);
157#endif
158}
159
160/*!
161 \fn bool QBluetoothServiceInfo::unregisterService()
162
163 Unregisters this service with the platform's Service Discovery Protocol (SDP) implementation.
164 After this, the service will no longer be findable by other devices through service discovery.
165
166 Returns true if the service is successfully unregistered, otherwise returns false.
167*/
168
169bool QBluetoothServiceInfo::unregisterService()
170{
171 return d_ptr->unregisterService();
172}
173
174
175/*!
176 \fn void QBluetoothServiceInfo::setAttribute(quint16 attributeId, const QBluetoothUuid &value)
177
178 This is a convenience function.
179
180 Sets the attribute identified by \a attributeId to \a value.
181
182 If the service information is already registered with the platform's SDP database,
183 the database entry will not be updated until \l registerService() was called again.
184*/
185
186/*!
187 \fn void QBluetoothServiceInfo::setAttribute(quint16 attributeId, const QBluetoothServiceInfo::Sequence &value)
188
189 This is a convenience function.
190
191 Sets the attribute identified by \a attributeId to \a value.
192
193 If the service information is already registered with the platform's SDP database,
194 the database entry will not be updated until \l registerService() was called again.
195*/
196
197/*!
198 \fn void QBluetoothServiceInfo::setAttribute(quint16 attributeId, const QBluetoothServiceInfo::Alternative &value)
199
200 This is a convenience function.
201
202 Sets the attribute identified by \a attributeId to \a value.
203
204 If the service information is already registered with the platform's SDP database,
205 the database entry will not be updated until \l registerService() was called again.
206*/
207
208/*!
209 \fn void QBluetoothServiceInfo::setServiceName(const QString &name)
210
211 This is a convenience function. It is equivalent to calling
212 setAttribute(QBluetoothServiceInfo::ServiceName, name).
213
214 Sets the service name in the primary language to \a name.
215
216 \sa serviceName(), setAttribute()
217*/
218
219/*!
220 \fn QString QBluetoothServiceInfo::serviceName() const
221
222 This is a convenience function. It is equivalent to calling
223 attribute(QBluetoothServiceInfo::ServiceName).toString().
224
225 Returns the service name in the primary language.
226
227 \sa setServiceName(), attribute()
228*/
229
230/*!
231 \fn void QBluetoothServiceInfo::setServiceDescription(const QString &description)
232
233 This is a convenience function. It is equivalent to calling
234 setAttribute(QBluetoothServiceInfo::ServiceDescription, description).
235
236 Sets the service description in the primary language to \a description.
237
238 \sa serviceDescription(), setAttribute()
239*/
240
241/*!
242 \fn QString QBluetoothServiceInfo::serviceDescription() const
243
244 This is a convenience function. It is equivalent to calling
245 attribute(QBluetoothServiceInfo::ServiceDescription).toString().
246
247 Returns the service description in the primary language.
248
249 \sa setServiceDescription(), attribute()
250*/
251
252/*!
253 \fn void QBluetoothServiceInfo::setServiceProvider(const QString &provider)
254
255 This is a convenience function. It is equivalent to calling
256 setAttribute(QBluetoothServiceInfo::ServiceProvider, provider).
257
258 Sets the service provider in the primary language to \a provider.
259
260 \sa serviceProvider(), setAttribute()
261*/
262
263/*!
264 \fn QString QBluetoothServiceInfo::serviceProvider() const
265
266 This is a convenience function. It is equivalent to calling
267 attribute(QBluetoothServiceInfo::ServiceProvider).toString().
268
269 Returns the service provider in the primary language.
270
271 \sa setServiceProvider(), attribute()
272*/
273
274/*!
275 \fn void QBluetoothServiceInfo::setServiceAvailability(quint8 availability)
276
277 This is a convenience function. It is equivalent to calling
278 setAttribute(QBluetoothServiceInfo::ServiceAvailability, availability).
279
280 Sets the availabiltiy of the service to \a availability.
281
282 \sa serviceAvailability(), setAttribute()
283*/
284
285/*!
286 \fn quint8 QBluetoothServiceInfo::serviceAvailability() const
287
288 This is a convenience function. It is equivalent to calling
289 attribute(QBluetoothServiceInfo::ServiceAvailability).toUInt().
290
291 Returns the availability of the service.
292
293 \sa setServiceAvailability(), attribute()
294*/
295
296/*!
297 \fn void QBluetoothServiceInfo::setServiceUuid(const QBluetoothUuid &uuid)
298
299 This is a convenience function. It is equivalent to calling
300 setAttribute(QBluetoothServiceInfo::ServiceId, uuid).
301
302 Sets the custom service UUID to \a uuid. This function should not be used
303 to set a standardized service UUID.
304
305 \sa serviceUuid(), setAttribute()
306*/
307
308/*!
309 \fn QBluetoothUuid QBluetoothServiceInfo::serviceUuid() const
310
311 This is a convenience function. It is equivalent to calling
312 attribute(QBluetoothServiceInfo::ServiceId).value<QBluetoothUuid>().
313
314 Returns the custom UUID of the service. This UUID may be null.
315 UUIDs based on \l{https://bluetooth.org}{Bluetooth SIG standards}
316 should be retrieved via \l serviceClassUuids().
317
318 \sa setServiceUuid(), attribute()
319*/
320
321/*!
322 Construct a new invalid QBluetoothServiceInfo;
323*/
324QBluetoothServiceInfo::QBluetoothServiceInfo()
325 : d_ptr(QSharedPointer<QBluetoothServiceInfoPrivate>::create())
326{
327 qRegisterMetaType<QBluetoothServiceInfo>();
328}
329
330/*!
331 Construct a new QBluetoothServiceInfo that is a copy of \a other.
332
333 The two copies continue to share the same underlying data which does not detach
334 upon write.
335*/
336QBluetoothServiceInfo::QBluetoothServiceInfo(const QBluetoothServiceInfo &other)
337 : d_ptr(other.d_ptr)
338{
339}
340
341/*!
342 Destroys the QBluetoothServiceInfo object.
343*/
344QBluetoothServiceInfo::~QBluetoothServiceInfo()
345{
346}
347
348/*!
349 Returns true if the QBluetoothServiceInfo object is valid, otherwise returns false.
350
351 An invalid QBluetoothServiceInfo object will have no attributes.
352*/
353bool QBluetoothServiceInfo::isValid() const
354{
355 return !d_ptr->attributes.isEmpty();
356}
357
358/*!
359 Returns true if the QBluetoothServiceInfo object is considered complete, otherwise returns false.
360
361 A complete QBluetoothServiceInfo object contains a ProtocolDescriptorList attribute.
362*/
363bool QBluetoothServiceInfo::isComplete() const
364{
365 return d_ptr->attributes.contains(key: ProtocolDescriptorList);
366}
367
368/*!
369 Returns the address of the Bluetooth device that provides this service.
370*/
371QBluetoothDeviceInfo QBluetoothServiceInfo::device() const
372{
373 return d_ptr->deviceInfo;
374}
375
376/*!
377 Sets the Bluetooth device that provides this service to \a device.
378*/
379void QBluetoothServiceInfo::setDevice(const QBluetoothDeviceInfo &device)
380{
381 d_ptr->deviceInfo = device;
382}
383
384/*!
385 Sets the attribute identified by \a attributeId to \a value.
386
387 If the service information is already registered with the platform's SDP database,
388 the database entry will not be updated until \l registerService() was called again.
389
390 \note If an attribute expectes a byte-encoded value (e.g. Bluetooth HID services),
391 it should be set as QByteArray.
392
393 \sa isRegistered(), registerService()
394*/
395void QBluetoothServiceInfo::setAttribute(quint16 attributeId, const QVariant &value)
396{
397 d_ptr->attributes[attributeId] = value;
398}
399
400/*!
401 Returns the value of the attribute \a attributeId.
402*/
403QVariant QBluetoothServiceInfo::attribute(quint16 attributeId) const
404{
405 return d_ptr->attributes.value(key: attributeId);
406}
407
408/*!
409 Returns a list of all attribute ids that the QBluetoothServiceInfo object has.
410*/
411QList<quint16> QBluetoothServiceInfo::attributes() const
412{
413 return d_ptr->attributes.keys();
414}
415
416/*!
417 Returns true if the QBluetoothServiceInfo object contains the attribute \a attributeId, otherwise returns
418 false.
419*/
420bool QBluetoothServiceInfo::contains(quint16 attributeId) const
421{
422 return d_ptr->attributes.contains(key: attributeId);
423}
424
425/*!
426 Removes the attribute \a attributeId from the QBluetoothServiceInfo object.
427
428 If the service information is already registered with the platforms SDP database,
429 the database entry will not be updated until \l registerService() was called again.
430*/
431void QBluetoothServiceInfo::removeAttribute(quint16 attributeId)
432{
433 d_ptr->attributes.remove(key: attributeId);
434}
435
436/*!
437 Returns the protocol that the QBluetoothServiceInfo object uses.
438*/
439QBluetoothServiceInfo::Protocol QBluetoothServiceInfo::socketProtocol() const
440{
441 QBluetoothServiceInfo::Sequence parameters = protocolDescriptor(protocol: QBluetoothUuid::ProtocolUuid::Rfcomm);
442 if (!parameters.isEmpty())
443 return RfcommProtocol;
444
445 parameters = protocolDescriptor(protocol: QBluetoothUuid::ProtocolUuid::L2cap);
446 if (!parameters.isEmpty())
447 return L2capProtocol;
448
449 return UnknownProtocol;
450}
451
452/*!
453 This is a convenience function. Returns the protocol/service multiplexer for services which
454 support the L2CAP protocol, otherwise returns -1.
455
456 This function is equivalent to extracting the information from
457 QBluetoothServiceInfo::Sequence returned by
458 QBluetoothServiceInfo::attribute(QBluetoothServiceInfo::ProtocolDescriptorList).
459*/
460int QBluetoothServiceInfo::protocolServiceMultiplexer() const
461{
462 QBluetoothServiceInfo::Sequence parameters = protocolDescriptor(protocol: QBluetoothUuid::ProtocolUuid::L2cap);
463
464 if (parameters.isEmpty())
465 return -1;
466 else if (parameters.size() == 1)
467 return 0;
468 else
469 return parameters.at(i: 1).toUInt();
470}
471
472/*!
473 This is a convenience function. Returns the server channel for services which support the
474 RFCOMM protocol, otherwise returns -1.
475
476 This function is equivalent to extracting the information from
477 QBluetoothServiceInfo::Sequence returned by
478 QBluetoothServiceInfo::attribute(QBluetootherServiceInfo::ProtocolDescriptorList).
479*/
480int QBluetoothServiceInfo::serverChannel() const
481{
482 return d_ptr->serverChannel();
483}
484
485/*!
486 Returns the protocol parameters as a QBluetoothServiceInfo::Sequence for protocol \a protocol.
487
488 An empty QBluetoothServiceInfo::Sequence is returned if \a protocol is not supported.
489*/
490QBluetoothServiceInfo::Sequence QBluetoothServiceInfo::protocolDescriptor(QBluetoothUuid::ProtocolUuid protocol) const
491{
492 return d_ptr->protocolDescriptor(protocol);
493}
494
495/*!
496 Returns a list of UUIDs describing the service classes that this service conforms to.
497
498 This is a convenience function. It is equivalent to calling
499 attribute(QBluetoothServiceInfo::ServiceClassIds).value<QBluetoothServiceInfo::Sequence>()
500 and subsequently iterating over its QBluetoothUuid entries.
501
502 \sa attribute()
503*/
504QList<QBluetoothUuid> QBluetoothServiceInfo::serviceClassUuids() const
505{
506 QList<QBluetoothUuid> results;
507
508 const QVariant var = attribute(attributeId: QBluetoothServiceInfo::ServiceClassIds);
509 if (!var.isValid())
510 return results;
511
512 const QBluetoothServiceInfo::Sequence seq = var.value<QBluetoothServiceInfo::Sequence>();
513 for (qsizetype i = 0; i < seq.size(); ++i)
514 results.append(t: seq.at(i).value<QBluetoothUuid>());
515
516 return results;
517}
518
519/*!
520 Makes a copy of the \a other and assigns it to this QBluetoothServiceInfo object.
521 The two copies continue to share the same service and registration details.
522*/
523QBluetoothServiceInfo &QBluetoothServiceInfo::operator=(const QBluetoothServiceInfo &other)
524{
525 d_ptr = other.d_ptr;
526
527 return *this;
528}
529
530static void dumpAttributeVariant(QDebug dbg, const QVariant &var, const QString& indent)
531{
532 switch (var.typeId()) {
533 case QMetaType::Void:
534 dbg << QString::asprintf(format: "%sEmpty\n", indent.toUtf8().constData());
535 break;
536 case QMetaType::UChar:
537 dbg << QString::asprintf(format: "%suchar %u\n", indent.toUtf8().constData(), var.toUInt());
538 break;
539 case QMetaType::UShort:
540 dbg << QString::asprintf(format: "%sushort %u\n", indent.toUtf8().constData(), var.toUInt());
541 break;
542 case QMetaType::UInt:
543 dbg << QString::asprintf(format: "%suint %u\n", indent.toUtf8().constData(), var.toUInt());
544 break;
545 case QMetaType::Char:
546 dbg << QString::asprintf(format: "%schar %d\n", indent.toUtf8().constData(), var.toInt());
547 break;
548 case QMetaType::Short:
549 dbg << QString::asprintf(format: "%sshort %d\n", indent.toUtf8().constData(), var.toInt());
550 break;
551 case QMetaType::Int:
552 dbg << QString::asprintf(format: "%sint %d\n", indent.toUtf8().constData(), var.toInt());
553 break;
554 case QMetaType::QString:
555 dbg << QString::asprintf(format: "%sstring %s\n", indent.toUtf8().constData(),
556 var.toString().toUtf8().constData());
557 break;
558 case QMetaType::QByteArray:
559 dbg << QString::asprintf(format: "%sbytearray %s\n", indent.toUtf8().constData(),
560 var.toByteArray().toHex().constData());
561 break;
562 case QMetaType::Bool:
563 dbg << QString::asprintf(format: "%sbool %d\n", indent.toUtf8().constData(), var.toBool());
564 break;
565 case QMetaType::QUrl:
566 dbg << QString::asprintf(format: "%surl %s\n", indent.toUtf8().constData(),
567 var.toUrl().toString().toUtf8().constData());
568 break;
569 default:
570 if (var.typeId() == qMetaTypeId<QBluetoothUuid>()) {
571 QBluetoothUuid uuid = var.value<QBluetoothUuid>();
572 switch (uuid.minimumSize()) {
573 case 0:
574 dbg << QString::asprintf(format: "%suuid NULL\n", indent.toUtf8().constData());
575 break;
576 case 2:
577 dbg << QString::asprintf(format: "%suuid2 %04x\n", indent.toUtf8().constData(),
578 uuid.toUInt16());
579 break;
580 case 4:
581 dbg << QString::asprintf(format: "%suuid %08x\n", indent.toUtf8().constData(),
582 uuid.toUInt32());
583 break;
584 case 16:
585 dbg << QString::asprintf(format: "%suuid %s\n",
586 indent.toUtf8().constData(),
587 uuid.toByteArray(mode: QUuid::Id128).constData());
588 break;
589 default:
590 dbg << QString::asprintf(format: "%suuid ???\n", indent.toUtf8().constData());
591 }
592 } else if (var.typeId() == qMetaTypeId<QBluetoothServiceInfo::Sequence>()) {
593 dbg << QString::asprintf(format: "%sSequence\n", indent.toUtf8().constData());
594 const QBluetoothServiceInfo::Sequence *sequence = static_cast<const QBluetoothServiceInfo::Sequence *>(var.data());
595 for (const QVariant &v : *sequence)
596 dumpAttributeVariant(dbg, var: v, indent: indent + QLatin1Char('\t'));
597 } else if (var.typeId() == qMetaTypeId<QBluetoothServiceInfo::Alternative>()) {
598 dbg << QString::asprintf(format: "%sAlternative\n", indent.toUtf8().constData());
599 const QBluetoothServiceInfo::Alternative *alternative = static_cast<const QBluetoothServiceInfo::Alternative *>(var.data());
600 for (const QVariant &v : *alternative)
601 dumpAttributeVariant(dbg, var: v, indent: indent + QLatin1Char('\t'));
602 } else {
603 dbg << QString::asprintf(format: "%sunknown variant type %d\n", indent.toUtf8().constData(), var.typeId());
604 }
605 }
606}
607
608#ifndef QT_NO_DEBUG_STREAM
609QDebug QBluetoothServiceInfo::streamingOperator(QDebug dbg, const QBluetoothServiceInfo &info)
610{
611 QDebugStateSaver saver(dbg);
612 dbg.noquote() << "\n";
613 const QList<quint16> attributes = info.attributes();
614 for (quint16 id : attributes) {
615 dumpAttributeVariant(dbg, var: info.attribute(attributeId: id), QStringLiteral("(%1)\t").arg(a: id));
616 }
617 return dbg;
618}
619#endif
620
621QBluetoothServiceInfo::Sequence QBluetoothServiceInfoPrivate::protocolDescriptor(QBluetoothUuid::ProtocolUuid protocol) const
622{
623 if (!attributes.contains(key: QBluetoothServiceInfo::ProtocolDescriptorList))
624 return QBluetoothServiceInfo::Sequence();
625
626 const QBluetoothServiceInfo::Sequence sequence
627 = attributes.value(key: QBluetoothServiceInfo::ProtocolDescriptorList).value<QBluetoothServiceInfo::Sequence>();
628 for (const QVariant &v : sequence) {
629 QBluetoothServiceInfo::Sequence parameters = v.value<QBluetoothServiceInfo::Sequence>();
630 if (parameters.empty())
631 continue;
632 if (parameters.at(i: 0).userType() == qMetaTypeId<QBluetoothUuid>()) {
633 if (parameters.at(i: 0).value<QBluetoothUuid>() == protocol)
634 return parameters;
635 }
636 }
637
638 return QBluetoothServiceInfo::Sequence();
639}
640
641int QBluetoothServiceInfoPrivate::serverChannel() const
642{
643 QBluetoothServiceInfo::Sequence parameters = protocolDescriptor(protocol: QBluetoothUuid::ProtocolUuid::Rfcomm);
644
645 if (parameters.isEmpty())
646 return -1;
647 else if (parameters.size() == 1)
648 return 0;
649 else
650 return parameters.at(i: 1).toUInt();
651}
652
653QT_END_NAMESPACE
654

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