diff options
-rw-r--r-- | src/bluetooth/qbluetoothserviceinfo.cpp | 9 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothserviceinfo_bluez.cpp | 17 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothserviceinfo_osx.mm | 59 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothserviceinfo_winrt.cpp | 8 | ||||
-rw-r--r-- | tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp | 45 |
5 files changed, 105 insertions, 33 deletions
diff --git a/src/bluetooth/qbluetoothserviceinfo.cpp b/src/bluetooth/qbluetoothserviceinfo.cpp index 74b17ac4..7c3780ec 100644 --- a/src/bluetooth/qbluetoothserviceinfo.cpp +++ b/src/bluetooth/qbluetoothserviceinfo.cpp @@ -413,6 +413,9 @@ void QBluetoothServiceInfo::setDevice(const QBluetoothDeviceInfo &device) If the service information is already registered with the platform's SDP database, the database entry will not be updated until \l registerService() was called again. + \note If an attribute expectes a byte-encoded value (e.g. Bluetooth HID services), + it should be set as QByteArray. + \sa isRegistered(), registerService() */ void QBluetoothServiceInfo::setAttribute(quint16 attributeId, const QVariant &value) @@ -578,6 +581,10 @@ static void dumpAttributeVariant(QDebug dbg, const QVariant &var, const QString& dbg << QString::asprintf("%sstring %s\n", indent.toUtf8().constData(), var.toString().toUtf8().constData()); break; + case QMetaType::QByteArray: + dbg << QString::asprintf("%sbytearray %s\n", indent.toUtf8().constData(), + var.toByteArray().toHex().constData()); + break; case QMetaType::Bool: dbg << QString::asprintf("%sbool %d\n", indent.toUtf8().constData(), var.toBool()); break; @@ -631,7 +638,7 @@ QDebug operator<<(QDebug dbg, const QBluetoothServiceInfo &info) { QDebugStateSaver saver(dbg); dbg.noquote() << "\n"; - QList<quint16> attributes = info.attributes(); + const QList<quint16> attributes = info.attributes(); for (quint16 id : attributes) { dumpAttributeVariant(dbg, info.attribute(id), QStringLiteral("(%1)\t").arg(id)); } diff --git a/src/bluetooth/qbluetoothserviceinfo_bluez.cpp b/src/bluetooth/qbluetoothserviceinfo_bluez.cpp index 09829b13..5f57e19e 100644 --- a/src/bluetooth/qbluetoothserviceinfo_bluez.cpp +++ b/src/bluetooth/qbluetoothserviceinfo_bluez.cpp @@ -103,17 +103,16 @@ static void writeAttribute(QXmlStreamWriter *stream, const QVariant &attribute) QString::number(attribute.value<qint32>(), 16)); //stream->writeAttribute(QStringLiteral("name"), foo); break; + case QMetaType::QByteArray: + stream->writeEmptyElement(QStringLiteral("text")); + stream->writeAttribute(QStringLiteral("value"), + QString::fromLatin1(attribute.value<QByteArray>().toHex().constData())); + stream->writeAttribute(QStringLiteral("encoding"), QStringLiteral("hex")); + break; case QMetaType::QString: stream->writeEmptyElement(QStringLiteral("text")); - if (/* require hex encoding */ false) { - stream->writeAttribute(QStringLiteral("value"), QString::fromLatin1( - attribute.value<QString>().toUtf8().toHex().constData())); - stream->writeAttribute(QStringLiteral("encoding"), QStringLiteral("hex")); - } else { - stream->writeAttribute(QStringLiteral("value"), attribute.value<QString>()); - stream->writeAttribute(QStringLiteral("encoding"), QStringLiteral("normal")); - } - //stream->writeAttribute(QStringLiteral("name"), foo); + stream->writeAttribute(QStringLiteral("value"), attribute.value<QString>()); + stream->writeAttribute(QStringLiteral("encoding"), QStringLiteral("normal")); break; case QMetaType::Bool: stream->writeEmptyElement(QStringLiteral("boolean")); diff --git a/src/bluetooth/qbluetoothserviceinfo_osx.mm b/src/bluetooth/qbluetoothserviceinfo_osx.mm index 27da70fc..34de4695 100644 --- a/src/bluetooth/qbluetoothserviceinfo_osx.mm +++ b/src/bluetooth/qbluetoothserviceinfo_osx.mm @@ -304,80 +304,93 @@ QBluetoothServiceInfo &QBluetoothServiceInfo::operator=(const QBluetoothServiceI return *this; } -static void dumpAttributeVariant(const QVariant &var, const QString indent) +static void dumpAttributeVariant(QDebug dbg, const QVariant &var, const QString& indent) { switch (int(var.type())) { case QMetaType::Void: - qDebug("%sEmpty", indent.toLocal8Bit().constData()); + dbg << QString::asprintf("%sEmpty\n", indent.toUtf8().constData()); break; case QMetaType::UChar: - qDebug("%suchar %u", indent.toLocal8Bit().constData(), var.toUInt()); + dbg << QString::asprintf("%suchar %u\n", indent.toUtf8().constData(), var.toUInt()); break; case QMetaType::UShort: - qDebug("%sushort %u", indent.toLocal8Bit().constData(), var.toUInt()); + dbg << QString::asprintf("%sushort %u\n", indent.toUtf8().constData(), var.toUInt()); + break; case QMetaType::UInt: - qDebug("%suint %u", indent.toLocal8Bit().constData(), var.toUInt()); + dbg << QString::asprintf("%suint %u\n", indent.toUtf8().constData(), var.toUInt()); break; case QMetaType::Char: - qDebug("%schar %d", indent.toLocal8Bit().constData(), var.toInt()); + dbg << QString::asprintf("%schar %d\n", indent.toUtf8().constData(), var.toInt()); break; case QMetaType::Short: - qDebug("%sshort %d", indent.toLocal8Bit().constData(), var.toInt()); + dbg << QString::asprintf("%sshort %d\n", indent.toUtf8().constData(), var.toInt()); break; case QMetaType::Int: - qDebug("%sint %d", indent.toLocal8Bit().constData(), var.toInt()); + dbg << QString::asprintf("%sint %d\n", indent.toUtf8().constData(), var.toInt()); break; case QMetaType::QString: - qDebug("%sstring %s", indent.toLocal8Bit().constData(), var.toString().toLocal8Bit().constData()); + dbg << QString::asprintf("%sstring %s\n", indent.toUtf8().constData(), + var.toString().toUtf8().constData()); + break; + case QMetaType::QByteArray: + dbg << QString::asprintf("%sbytearray %s\n", indent.toUtf8().constData(), + var.toByteArray().toHex().constData()); break; case QMetaType::Bool: - qDebug("%sbool %d", indent.toLocal8Bit().constData(), var.toBool()); + dbg << QString::asprintf("%sbool %d\n", indent.toUtf8().constData(), var.toBool()); break; case QMetaType::QUrl: - qDebug("%surl %s", indent.toLocal8Bit().constData(), var.toUrl().toString().toLocal8Bit().constData()); + dbg << QString::asprintf("%surl %s\n", indent.toUtf8().constData(), + var.toUrl().toString().toUtf8().constData()); break; case QVariant::UserType: if (var.userType() == qMetaTypeId<QBluetoothUuid>()) { QBluetoothUuid uuid = var.value<QBluetoothUuid>(); switch (uuid.minimumSize()) { case 0: - qDebug("%suuid NULL", indent.toLocal8Bit().constData()); + dbg << QString::asprintf("%suuid NULL\n", indent.toUtf8().constData()); break; case 2: - qDebug("%suuid %04x", indent.toLocal8Bit().constData(), uuid.toUInt16()); + dbg << QString::asprintf("%suuid2 %04x\n", indent.toUtf8().constData(), + uuid.toUInt16()); break; case 4: - qDebug("%suuid %08x", indent.toLocal8Bit().constData(), uuid.toUInt32()); + dbg << QString::asprintf("%suuid %08x\n", indent.toUtf8().constData(), + uuid.toUInt32()); break; case 16: - qDebug("%suuid %s", indent.toLocal8Bit().constData(), QByteArray(reinterpret_cast<const char *>(uuid.toUInt128().data), 16).toHex().constData()); + dbg << QString::asprintf("%suuid %s\n", + indent.toUtf8().constData(), + QByteArray(reinterpret_cast<const char *>(uuid.toUInt128().data), 16).toHex().constData()); break; default: - qDebug("%suuid ???", indent.toLocal8Bit().constData()); - ; + dbg << QString::asprintf("%suuid ???\n", indent.toUtf8().constData()); } } else if (var.userType() == qMetaTypeId<QBluetoothServiceInfo::Sequence>()) { - qDebug("%sSequence", indent.toLocal8Bit().constData()); + dbg << QString::asprintf("%sSequence\n", indent.toUtf8().constData()); const QBluetoothServiceInfo::Sequence *sequence = static_cast<const QBluetoothServiceInfo::Sequence *>(var.data()); for (const QVariant &v : *sequence) - dumpAttributeVariant(v, indent + QLatin1Char('\t')); + dumpAttributeVariant(dbg, v, indent + QLatin1Char('\t')); } else if (var.userType() == qMetaTypeId<QBluetoothServiceInfo::Alternative>()) { - qDebug("%sAlternative", indent.toLocal8Bit().constData()); + dbg << QString::asprintf("%sAlternative\n", indent.toUtf8().constData()); const QBluetoothServiceInfo::Alternative *alternative = static_cast<const QBluetoothServiceInfo::Alternative *>(var.data()); for (const QVariant &v : *alternative) - dumpAttributeVariant(v, indent + QLatin1Char('\t')); + dumpAttributeVariant(dbg, v, indent + QLatin1Char('\t')); } break; default: - qDebug("%sunknown variant type %d", indent.toLocal8Bit().constData(), var.userType()); + dbg << QString::asprintf("%sunknown variant type %d\n", indent.toUtf8().constData(), + var.userType()); } } QDebug operator << (QDebug dbg, const QBluetoothServiceInfo &info) { + QDebugStateSaver saver(dbg); + dbg.noquote() << "\n"; const QList<quint16> attributes = info.attributes(); for (quint16 id : attributes) { - dumpAttributeVariant(info.attribute(id), QString::fromLatin1("(%1)\t").arg(id)); + dumpAttributeVariant(dbg, info.attribute(id), QString::fromLatin1("(%1)\t").arg(id)); } return dbg; } diff --git a/src/bluetooth/qbluetoothserviceinfo_winrt.cpp b/src/bluetooth/qbluetoothserviceinfo_winrt.cpp index 45262735..e806096f 100644 --- a/src/bluetooth/qbluetoothserviceinfo_winrt.cpp +++ b/src/bluetooth/qbluetoothserviceinfo_winrt.cpp @@ -297,6 +297,14 @@ static ComPtr<IBuffer> bufferFromAttribute(const QVariant &attribute) hr = writer->WriteInt64(attribute.value<qint64>()); Q_ASSERT_SUCCEEDED(hr); break; + case QMetaType::QByteArray: { + qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::QByteArray:" << attribute.value<QString>(); + const QString stringValue = QString::fromLatin1(attribute.value<QByteArray>().toHex()); + const bool writeSuccess = writeStringHelper(stringValue, writer); + if (!writeSuccess) + return nullptr; + break; + } case QMetaType::QString: { qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::QString:" << attribute.value<QString>(); const QString stringValue = attribute.value<QString>(); diff --git a/tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp b/tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp index ae8cf5d0..10c4bd3b 100644 --- a/tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp +++ b/tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp @@ -61,6 +61,8 @@ private slots: void tst_assignment(); void tst_serviceClassUuids(); + + void tst_writeByteArray(); }; tst_QBluetoothServiceInfo::tst_QBluetoothServiceInfo() @@ -385,6 +387,49 @@ void tst_QBluetoothServiceInfo::tst_serviceClassUuids() QCOMPARE(svclids.at(1), QBluetoothUuid(QBluetoothUuid::SerialPort)); } +static QByteArray debugOutput; + +void debugHandler(QtMsgType type, const QMessageLogContext &, const QString &msg) +{ + switch (type) { + case QtDebugMsg : + debugOutput = msg.toLocal8Bit(); + break; + default: + break; + } +} + +void tst_QBluetoothServiceInfo::tst_writeByteArray() +{ + // We cannot directly test the produced XML output for Bluez + // as there no public API to retrieve it and it would be Bluez specific. + // However we can check the debug output. + // It should contain a qbyteArray rather than a string. In the XML the QByteArray + // is converted to a text tag with hex encoding. + + const QByteArray expected("\n (518)\tSequence\n (518)\t\tSequence\n (518)\t\t\tuchar 34\n (518)\t\t\tbytearray 05010906a101850105079508750119e029e7150025018102950175088103050795067508150026ff00190029ff8100050895057501190129059102950175039103c005010902a10185020901a1000509190129031500250175019503810275059501810105010930093109381581257f750895038106c0c0\n"); + + const QByteArray hidDescriptor = + QByteArray::fromHex("05010906a101850105079508750119e029e7150025018102950175088103050795067508150026FF00190029FF8100050895057501190129059102950175039103c005010902a10185020901a1000509190129031500250175019503810275059501810105010930093109381581257f750895038106c0c0"); + const QBluetoothServiceInfo::Sequence hidDescriptorList({ + QVariant::fromValue(quint8(0x22)), // Report type + QByteArray(hidDescriptor) // Descriptor array + }); + const QBluetoothServiceInfo::Sequence hidDescriptorListSeq({ + QVariant::fromValue(hidDescriptorList) + }); + QBluetoothServiceInfo srvInfo; + srvInfo.setAttribute(0x0206, QVariant::fromValue(hidDescriptorListSeq)); + + const QVariant attribute = srvInfo.attribute(0x0206); + debugOutput.clear(); + qInstallMessageHandler(debugHandler); + qDebug() << srvInfo; + qInstallMessageHandler(nullptr); + QCOMPARE(debugOutput, expected); +} + QTEST_MAIN(tst_QBluetoothServiceInfo) #include "tst_qbluetoothserviceinfo.moc" |