From a084e2160a345162681af984d9c265f619be7124 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 20 Apr 2016 21:23:01 +0200 Subject: do not enable example installs explicitly any more it's done centrally now. Change-Id: I2f2b9ca69f46d681ebe4c04ddbf836814a4056d6 Reviewed-by: Alex Blasche --- .qmake.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index 4d3d5bff..21c63db3 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,4 +1,3 @@ load(qt_build_config) -CONFIG += qt_example_installs MODULE_VERSION = 5.6.2 -- cgit v1.2.3 From b9aae35fab6a256705fc3e2bd8d001075fc28efa Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 19 May 2016 19:20:55 +0200 Subject: QNearFieldTagType1Private: take more care over m_tlv{Writ,Read}er. The writer wasn't initialized; Coverity grumbled (CID 22323). Various stanzas take for granted that one or other is set; assert there. Various stanzas created each afresh, without considering they might be leaking a prior one; delete first (could probably have asserted == 0 instead). Change-Id: I4c792fbbd611e06c28235ceafee40cc18268c60d Reviewed-by: Alex Blasche --- src/nfc/qnearfieldtagtype1.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/nfc/qnearfieldtagtype1.cpp b/src/nfc/qnearfieldtagtype1.cpp index cbd1c1a6..778deda5 100644 --- a/src/nfc/qnearfieldtagtype1.cpp +++ b/src/nfc/qnearfieldtagtype1.cpp @@ -76,7 +76,8 @@ public: QNearFieldTagType1Private(QNearFieldTagType1 *q) : q_ptr(q), m_readNdefMessageState(NotReadingNdefMessage), m_tlvReader(0), - m_writeNdefMessageState(NotWritingNdefMessage) + m_writeNdefMessageState(NotWritingNdefMessage), + m_tlvWriter(0) { } QNearFieldTagType1 *q_ptr; @@ -164,11 +165,13 @@ void QNearFieldTagType1Private::progressToNextNdefReadMessageState() } m_readNdefMessageState = NdefReadReadingTlv; + delete m_tlvReader; m_tlvReader = new QTlvReader(q); // fall through } case NdefReadReadingTlv: + Q_ASSERT(m_tlvReader); while (!m_tlvReader->atEnd()) { if (!m_tlvReader->readNext()) break; @@ -240,11 +243,13 @@ void QNearFieldTagType1Private::progressToNextNdefWriteMessageState() } m_writeNdefMessageState = NdefWriteReadingTlv; + delete m_tlvReader; m_tlvReader = new QTlvReader(q); // fall through } case NdefWriteReadingTlv: + Q_ASSERT(m_tlvReader); while (!m_tlvReader->atEnd()) { if (!m_tlvReader->readNext()) break; @@ -264,6 +269,7 @@ void QNearFieldTagType1Private::progressToNextNdefWriteMessageState() // fall through case NdefWriteWritingTlv: + delete m_tlvWriter; m_tlvWriter = new QTlvWriter(q); // write old TLVs @@ -282,6 +288,7 @@ void QNearFieldTagType1Private::progressToNextNdefWriteMessageState() // fall through case NdefWriteWritingTlvFlush: // flush the writer + Q_ASSERT(m_tlvWriter); if (m_tlvWriter->process(true)) { m_nextExpectedRequestId = QNearFieldTarget::RequestId(); m_writeNdefMessageState = NotWritingNdefMessage; -- cgit v1.2.3 From 968e683a59bdaf51ad0d12069ce68c4fad6190a1 Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Tue, 31 May 2016 09:25:06 +0200 Subject: Bluez: Cleanup internal states before sending notifications to API user The error(), finished() and canceled() signals notify the user about internal state changes. Signal handlers may call back into the same class instance that just emitted the signals. If the instance did not cleanup its internal state then the sudden reentry can cause weird behavior. Adds a comment that the pendingCancel & pendingStart behavior is to be removed in Qt6. It has little advantage and cuases lots of headaches. Unfortunately all backends exhibit the behavior and therefore every backend has to change accordingly. Task-number: QTBUG-51307 Change-Id: Ia5bf9efd0ed27e015361b10499ced069d16a9c93 Reviewed-by: Christian Kandeler --- src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp index 18accdf5..47323e85 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp @@ -92,12 +92,19 @@ QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate() delete adapterBluez5; } +//TODO: Qt6 remove the pendingCancel/pendingStart logic as it is cumbersome. +// It is a behavior change across all platforms and was initially done +// for Bluez. The behavior should be similar to QBluetoothServiceDiscoveryAgent +// PendingCancel creates issues whereby the agent is still shutting down +// but isActive() below already returns false. This means the isActive() is +// out of sync with the finished() and cancel() signal. + bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const { if (pendingStart) return true; if (pendingCancel) - return false; + return false; //TODO Qt6: remove pending[Cancel|Start] logic (see comment above) return (adapter || adapterBluez5); } @@ -195,8 +202,8 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start() errorString = discoveryReply.error().message(); lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError; Q_Q(QBluetoothDeviceDiscoveryAgent); - emit q->error(lastError); qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "ERROR: " << errorString; + emit q->error(lastError); return; } } @@ -415,8 +422,8 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_propertyChanged(const QString &na adapter->deleteLater(); adapter = 0; - emit q->canceled(); pendingCancel = false; + emit q->canceled(); } else if (pendingStart) { adapter->deleteLater(); adapter = 0; @@ -492,8 +499,8 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_discoveryFinished() adapterBluez5 = 0; if (pendingCancel && !pendingStart) { - emit q->canceled(); pendingCancel = false; + emit q->canceled(); } else if (pendingStart) { pendingStart = false; pendingCancel = false; -- cgit v1.2.3 From e1a6ad73c5d5c731195967b7f682089da24e1719 Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Tue, 31 May 2016 13:46:46 +0200 Subject: Android: Don't progress device search when BTLE search is not supported This happens when the Android device does not support BTLE. Previously the device search agent progressed even when it claimed that it was done already. Change-Id: If14df70bba02703f5feb8bc9c0569f596defede9 Reviewed-by: Timur Pocheptsov --- src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp index d335dc7a..d401fa58 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp @@ -258,6 +258,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startLowEnergyScan() env->ExceptionClear(); m_active = NoScanActive; emit q->finished(); + return; } leScanner.setField("qtObject", reinterpret_cast(receiver)); @@ -268,6 +269,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startLowEnergyScan() qCWarning(QT_BT_ANDROID) << "Cannot start BTLE device scanner"; m_active = NoScanActive; emit q->finished(); + return; } if (!leScanTimeout) { -- cgit v1.2.3 From c347a3748af663da9e8e6ce5e233248b80217f96 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 19 May 2016 18:27:45 +0200 Subject: QBluetoothServiceDiscoveryAgent: set q_ptr in d_ptr's constructor. The agent class constructors were initializing the q_ptr member of their d_ptr; it is cleaner to pass this down to the d_ptr's constructor and let it do this itself. This also lets Coverity know that initialization actually does happen (CID 22330). In particular, it makes sure we can't leave it uninitialized, if an agent implementation happens to neglect to do so. Change-Id: Ie01046a5a113b5669e8e63c6a22f692cd3943ac0 Reviewed-by: Alex Blasche --- src/bluetooth/qbluetoothservicediscoveryagent.cpp | 8 ++++---- .../qbluetoothservicediscoveryagent_android.cpp | 6 ++++-- src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp | 6 ++++-- src/bluetooth/qbluetoothservicediscoveryagent_osx.mm | 16 +++++++++------- src/bluetooth/qbluetoothservicediscoveryagent_p.cpp | 12 ++++++++---- src/bluetooth/qbluetoothservicediscoveryagent_p.h | 3 ++- 6 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.cpp b/src/bluetooth/qbluetoothservicediscoveryagent.cpp index 0e478398..1ff30e52 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent.cpp @@ -143,9 +143,9 @@ QT_BEGIN_NAMESPACE local default Bluetooth adapter. */ QBluetoothServiceDiscoveryAgent::QBluetoothServiceDiscoveryAgent(QObject *parent) -: QObject(parent), d_ptr(new QBluetoothServiceDiscoveryAgentPrivate(QBluetoothAddress())) + : QObject(parent), + d_ptr(new QBluetoothServiceDiscoveryAgentPrivate(this, QBluetoothAddress())) { - d_ptr->q_ptr = this; } /*! @@ -161,9 +161,9 @@ QBluetoothServiceDiscoveryAgent::QBluetoothServiceDiscoveryAgent(QObject *parent \sa error() */ QBluetoothServiceDiscoveryAgent::QBluetoothServiceDiscoveryAgent(const QBluetoothAddress &deviceAdapter, QObject *parent) -: QObject(parent), d_ptr(new QBluetoothServiceDiscoveryAgentPrivate(deviceAdapter)) + : QObject(parent), + d_ptr(new QBluetoothServiceDiscoveryAgentPrivate(this, deviceAdapter)) { - d_ptr->q_ptr = this; if (!deviceAdapter.isNull()) { const QList localDevices = QBluetoothLocalDevice::allDevices(); foreach (const QBluetoothHostInfo &hostInfo, localDevices) { diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp index 47f3bd0b..b87605bc 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp @@ -48,11 +48,13 @@ QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID) QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate( - const QBluetoothAddress &/*deviceAdapter*/) + QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &/*deviceAdapter*/) : error(QBluetoothServiceDiscoveryAgent::NoError), state(Inactive), deviceDiscoveryAgent(0), mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery), - singleDevice(false), receiver(0), localDeviceReceiver(0) + singleDevice(false), receiver(0), localDeviceReceiver(0), + q_ptr(qp) + { QList devices = QBluetoothLocalDevice::allDevices(); Q_ASSERT(devices.count() <= 1); //Android only supports one device at the moment diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp index ae51d681..e24ee802 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp @@ -62,10 +62,12 @@ static inline void convertAddress(quint64 from, quint8 (&to)[6]) to[5] = (from >> 40) & 0xff; } -QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(const QBluetoothAddress &deviceAdapter) +QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate( + QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &deviceAdapter) : error(QBluetoothServiceDiscoveryAgent::NoError), m_deviceAdapterAddress(deviceAdapter), state(Inactive), deviceDiscoveryAgent(0), mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery), singleDevice(false), - manager(0), managerBluez5(0), adapter(0), device(0), sdpScannerProcess(0) + manager(0), managerBluez5(0), adapter(0), device(0), sdpScannerProcess(0), + q_ptr(qp) { if (isBluez5()) { managerBluez5 = new OrgFreedesktopDBusObjectManagerInterface( diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_osx.mm b/src/bluetooth/qbluetoothservicediscoveryagent_osx.mm index 0cf77d9d..c3d4a0e6 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_osx.mm +++ b/src/bluetooth/qbluetoothservicediscoveryagent_osx.mm @@ -62,7 +62,8 @@ public: ServiceDiscovery, }; - QBluetoothServiceDiscoveryAgentPrivate(const QBluetoothAddress &localAddress); + QBluetoothServiceDiscoveryAgentPrivate(QBluetoothServiceDiscoveryAgent *qp, + const QBluetoothAddress &localAddress); void startDeviceDiscovery(); void stopDeviceDiscovery(); @@ -110,8 +111,9 @@ private: OSXBluetooth::ObjCScopedPointer serviceInquiry; }; -QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(const QBluetoothAddress &localAddress) : - q_ptr(0), +QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate( + QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &localAddress) : + q_ptr(qp), error(QBluetoothServiceDiscoveryAgent::NoError), singleDevice(false), localAdapterAddress(localAddress), @@ -423,15 +425,15 @@ void QBluetoothServiceDiscoveryAgentPrivate::serviceDiscoveryFinished() } QBluetoothServiceDiscoveryAgent::QBluetoothServiceDiscoveryAgent(QObject *parent) -: QObject(parent), d_ptr(new QBluetoothServiceDiscoveryAgentPrivate(QBluetoothAddress())) +: QObject(parent), + d_ptr(new QBluetoothServiceDiscoveryAgentPrivate(this, QBluetoothAddress())) { - d_ptr->q_ptr = this; } QBluetoothServiceDiscoveryAgent::QBluetoothServiceDiscoveryAgent(const QBluetoothAddress &deviceAdapter, QObject *parent) -: QObject(parent), d_ptr(new QBluetoothServiceDiscoveryAgentPrivate(deviceAdapter)) +: QObject(parent), + d_ptr(new QBluetoothServiceDiscoveryAgentPrivate(this, deviceAdapter)) { - d_ptr->q_ptr = this; if (!deviceAdapter.isNull()) { const QList localDevices = QBluetoothLocalDevice::allDevices(); foreach (const QBluetoothHostInfo &hostInfo, localDevices) { diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_p.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_p.cpp index e4561492..397882bc 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_p.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent_p.cpp @@ -39,10 +39,14 @@ QT_BEGIN_NAMESPACE -QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(const QBluetoothAddress &deviceAdapter) - : error(QBluetoothServiceDiscoveryAgent::NoError), state(Inactive), - deviceDiscoveryAgent(0), mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery), - singleDevice(false) +QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate( + QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &deviceAdapter) + : error(QBluetoothServiceDiscoveryAgent::NoError), + state(Inactive), + deviceDiscoveryAgent(0), + mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery), + singleDevice(false), + q_ptr(qp) { #ifndef QT_IOS_BLUETOOTH printDummyWarning(); diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_p.h b/src/bluetooth/qbluetoothservicediscoveryagent_p.h index c4d5017a..c61c39a5 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_p.h +++ b/src/bluetooth/qbluetoothservicediscoveryagent_p.h @@ -87,7 +87,8 @@ public: ServiceDiscovery, }; - QBluetoothServiceDiscoveryAgentPrivate(const QBluetoothAddress &deviceAdapter); + QBluetoothServiceDiscoveryAgentPrivate(QBluetoothServiceDiscoveryAgent *qp, + const QBluetoothAddress &deviceAdapter); ~QBluetoothServiceDiscoveryAgentPrivate(); void startDeviceDiscovery(); -- cgit v1.2.3 From 3e4236996d0d961bb91d30eff10e9b2aa8b7d4a7 Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Fri, 3 Jun 2016 10:09:38 +0200 Subject: BlueZ4: Don't process stop discovery notification in unready state Multiple device discovery agents can influence each other as they monitor the same DBus BlueZ adapter. When one agent started and another just stopped/finished the discovery process, the newly started agent is caught in an unprepared state. The other use case where this might happen is when one agent stopped the discovery and another agent goes through the same start/stop cycle in very quick order, then the first agent may still have pending signals despiter adapter being deleted. In any case this patch simply ensures that an already inactive agent doesn't go through the finishing process again. Task-number: QTBUG-51307 Change-Id: If0e2b944f1ceadb9037179c4fde2f3f79741d0a5 Reviewed-by: dmnikola Reviewed-by: Christian Kandeler --- src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp index 47323e85..7ff57adf 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp @@ -432,6 +432,10 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_propertyChanged(const QString &na pendingCancel = false; start(); } else { + // happens when agent is created while other agent called StopDiscovery() + if (!adapter) + return; + if (useExtendedDiscovery) { useExtendedDiscovery = false; /* We don't use the Start/StopDiscovery combo here -- cgit v1.2.3 From 5e8994a4fa83f4c2795978f8b9ae893cefc69160 Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Thu, 2 Jun 2016 13:56:50 +0200 Subject: Make it more obvious what tags the NFC poster example expects. Task-number: QTBUG-53616 Change-Id: Ie3a87abc61100ac8fe0a5b671725f54ae28e1501 Reviewed-by: Martin Smith Reviewed-by: Leena Miettinen --- .../nfc/poster/doc/images/qml-poster-example.png | Bin 5110 -> 7946 bytes examples/nfc/poster/doc/src/poster.qdoc | 21 ++++++++++++++++++++- examples/nfc/poster/poster.qml | 14 +++++++++++++- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/examples/nfc/poster/doc/images/qml-poster-example.png b/examples/nfc/poster/doc/images/qml-poster-example.png index d3ead72e..8ed2292c 100644 Binary files a/examples/nfc/poster/doc/images/qml-poster-example.png and b/examples/nfc/poster/doc/images/qml-poster-example.png differ diff --git a/examples/nfc/poster/doc/src/poster.qdoc b/examples/nfc/poster/doc/src/poster.qdoc index a569f47a..26320f56 100644 --- a/examples/nfc/poster/doc/src/poster.qdoc +++ b/examples/nfc/poster/doc/src/poster.qdoc @@ -31,7 +31,7 @@ \brief A QML example about reading and displaying NFC Data Exchange Format (NDEF) messages. The QML Poster example displays the contents of specifically formatted NFC Data -Exchange Format (NDEF) messages read from an NFC Tag. The NDEF message should +Exchange Format (NDEF) messages read from an NFC Tag. The NDEF message must contain a URI record, an optional \c image/* MIME record, and one or more localized Text records. @@ -39,5 +39,24 @@ localized Text records. \include examples-run.qdocinc +\section1 Applying NDEF Filters + +The example is designed to display the content of a very specific type of NFC tag. +The tag must contain at least one URI record and one text record. If those two +record types do not exist, nothing will happen. Such filtering is applied via the +\l NearField type's filter property. The property accepts a list of \l NdefFilter objects. + +\snippet poster/poster.qml QML NDEF filtering + +\section1 Processing Found NDEF Messages + +Once an appropriate tag is found, the \l NearField::messageRecords property reflects the content. +It transports the list of found NDEF records. The QML snippet below +demonstrates how these records can be accessed: + +\snippet poster/poster.qml messageRecordsChanged 1 +\snippet poster/poster.qml messageRecordsChanged 2 +\snippet poster/poster.qml messageRecordsChanged 3 + \sa {Qt NFC} */ diff --git a/examples/nfc/poster/poster.qml b/examples/nfc/poster/poster.qml index a70a998b..d57ed5d9 100644 --- a/examples/nfc/poster/poster.qml +++ b/examples/nfc/poster/poster.qml @@ -62,13 +62,18 @@ Rectangle { } } + //! [QML NDEF filtering] filter: [ NdefFilter { type: "U"; typeNameFormat: NdefRecord.NfcRtd; maximum: 1 }, NdefFilter { type: "T"; typeNameFormat: NdefRecord.NfcRtd }, NdefFilter { typeNameFormat: NdefRecord.Mime; minimum: 0; maximum: 1 } ] + //! [QML NDEF filtering] + + //! [messageRecordsChanged 1] onMessageRecordsChanged: { + //! [messageRecordsChanged 1] posterText.text = ""; posterImage.source = ""; posterUrl.text = ""; @@ -76,6 +81,7 @@ Rectangle { var currentLocaleMatch = NdefTextRecord.LocaleMatchedNone; var i; var found = false; + //! [messageRecordsChanged 2] for (i = 0; i < messageRecords.length; ++i) { switch (messageRecords[i].typeNameFormat) { case NdefRecord.NfcRtd: @@ -102,18 +108,24 @@ Rectangle { if (!found) console.warn("Unknown NFC tag detected. Cannot display content.") } + //! [messageRecordsChanged 2] root.state = "show"; + //! [messageRecordsChanged 3] } + //! [messageRecordsChanged 3] } Text { id: touchText anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter - text: "Touch an NFC tag" + text: "Touch an NFC tag with at least one Text and one URI record." font.bold: true font.pointSize: 18 + wrapMode: Text.WordWrap + width: root.width*0.75 + horizontalAlignment: Text.AlignHCenter } Image { -- cgit v1.2.3 From f59d75eb8b161be9c58d1fe534afa2fa08cf4382 Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Fri, 3 Jun 2016 10:18:41 +0200 Subject: Make the usage of a dummy backend obvious in the QtBluetooth docs Task-number: QTBUG-53749 Change-Id: I6e7832b4a5a70bed153fb8b0718b3c66177ffd58 Reviewed-by: Martin Smith --- src/bluetooth/doc/src/bluetooth-index.qdoc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/bluetooth/doc/src/bluetooth-index.qdoc b/src/bluetooth/doc/src/bluetooth-index.qdoc index b0ba62a0..5fd96539 100644 --- a/src/bluetooth/doc/src/bluetooth-index.qdoc +++ b/src/bluetooth/doc/src/bluetooth-index.qdoc @@ -63,6 +63,19 @@ import statement in your \c .qml file: \section1 Related Information +\section2 Building Qt Bluetooth + +Despite the fact that the module can be built for all Qt platforms, +the module is not ported to all of them. Not supported platforms such as Windows desktop +employ a fake or dummy backend which is automatically selected when the +platform is not supported. The dummy backend reports appropriate error messages +and values which allow the Qt Bluetooth developer to detect at runtime that the +current platform is not supported. The dummy backend is also selected on Linux if +BlueZ development headers are not found during build time or Qt was built without +Qt D-Bus support. + +The usage of the dummy backend is highlighted via an appropriate warning while building and running. + \section2 Guides \list \li \l {Qt Bluetooth Overview}{Classic Bluetooth Overview} -- cgit v1.2.3 From be8c8951744558070d72665f111909fb32b70d4f Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Wed, 25 May 2016 16:49:57 +0200 Subject: Bluez5: Run SDP on target devices which do not support public scans PUBLIC_BROWSE_GROUP scans are not always supported. In such cases more targeted service scans are to be used. This patch modifies QBluetoothServiceDiscoveryAgent such that when a uuid filter is set targeted service scans are used rather than generic PUBLIC_BROWSE_GROUP ones. QBluetoothSocket always scans with an applied uuid filter and therefore directly benefits from the patch. Change-Id: I94997d2cf8f70fa7db5422d78c8bfdbe2aa1dbbc Task-number: QTBUG-53041 Reviewed-by: Timur Pocheptsov --- .../qbluetoothservicediscoveryagent_bluez.cpp | 10 +- src/tools/sdpscanner/main.cpp | 106 +++++++++++++++++---- 2 files changed, 99 insertions(+), 17 deletions(-) diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp index e24ee802..716d80be 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp @@ -214,15 +214,23 @@ void QBluetoothServiceDiscoveryAgentPrivate::runExternalSdpScan( sdpScannerProcess = new QProcess(q); sdpScannerProcess->setReadChannel(QProcess::StandardOutput); + if (QT_BT_BLUEZ().isDebugEnabled()) + sdpScannerProcess->setProcessChannelMode(QProcess::ForwardedErrorChannel); sdpScannerProcess->setProgram(fileInfo.canonicalFilePath()); q->connect(sdpScannerProcess, SIGNAL(finished(int,QProcess::ExitStatus)), q, SLOT(_q_sdpScannerDone(int,QProcess::ExitStatus))); - } QStringList arguments; arguments << remoteAddress.toString() << localAddress.toString(); + // No filter implies PUBLIC_BROWSE_GROUP based SDP scan + if (!uuidFilter.isEmpty()) { + arguments << QLatin1String("-u"); // cmd line option for list of uuids + foreach (const QBluetoothUuid& uuid, uuidFilter) + arguments << uuid.toString(); + } + sdpScannerProcess->setArguments(arguments); sdpScannerProcess->start(); } diff --git a/src/tools/sdpscanner/main.cpp b/src/tools/sdpscanner/main.cpp index 50870651..d7188880 100644 --- a/src/tools/sdpscanner/main.cpp +++ b/src/tools/sdpscanner/main.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -46,11 +47,14 @@ void usage() { fprintf(stderr, "Usage:\n"); - fprintf(stderr, "\tsdpscanner [Options]\n\n"); + fprintf(stderr, "\tsdpscanner [Options] ({uuids})\n\n"); fprintf(stderr, "Performs an SDP scan on remote device, using the SDP server\n" "represented by the local Bluetooth device.\n\n" "Options:\n" - " -p Show scan results in human-readable form\n"); + " -p Show scan results in human-readable form\n" + " -u [list of uuids] List of uuids which should be scanned for.\n" + " Each uuid must be enclosed in {}.\n" + " If the list is empty PUBLIC_BROWSE_GROUP scan is used.\n"); } #define BUFFER_SIZE 1024 @@ -269,6 +273,7 @@ int main(int argc, char **argv) } bool showHumanReadable = false; + std::vector targetServices; for (int i = 3; i < argc; i++) { if (argv[i][0] != '-') { @@ -281,12 +286,56 @@ int main(int argc, char **argv) case 'p': showHumanReadable = true; break; + case 'u': + i++; + + for ( ; i < argc && argv[i][0] == '{'; i++) + targetServices.push_back(argv[i]); + + i--; // outer loop increments again + break; default: fprintf(stderr, "Wrong argument: %s\n", argv[i]); usage(); return RETURN_USAGE; + } + } + std::vector uuids; + for (std::vector::const_iterator iter = targetServices.cbegin(); + iter != targetServices.cend(); ++iter) { + + uint128_t temp128; + uint16_t field1, field2, field3, field5; + uint32_t field0, field4; + + fprintf(stderr, "Target scan for %s\n", (*iter).c_str()); + if (sscanf((*iter).c_str(), "{%08x-%04hx-%04hx-%04hx-%08x%04hx}", &field0, + &field1, &field2, &field3, &field4, &field5) != 6) { + fprintf(stderr, "Skipping invalid uuid: %s\n", ((*iter).c_str())); + continue; } + + // we need uuid_t conversion based on + // http://www.spinics.net/lists/linux-bluetooth/msg20356.html + field0 = htonl(field0); + field4 = htonl(field4); + field1 = htons(field1); + field2 = htons(field2); + field3 = htons(field3); + field5 = htons(field5); + + uint8_t* temp = (uint8_t*) &temp128; + memcpy(&temp[0], &field0, 4); + memcpy(&temp[4], &field1, 2); + memcpy(&temp[6], &field2, 2); + memcpy(&temp[8], &field3, 2); + memcpy(&temp[10], &field4, 4); + memcpy(&temp[14], &field5, 2); + + uuid_t sdpUuid; + sdp_uuid128_create(&sdpUuid, &temp128); + uuids.push_back(sdpUuid); } sdp_session_t *session = sdp_connect( &local, &remote, SDP_RETRY_IF_BUSY); @@ -301,27 +350,52 @@ int main(int argc, char **argv) } // set the filter for service matches - uuid_t publicBrowseGroupUuid; - sdp_uuid16_create(&publicBrowseGroupUuid, PUBLIC_BROWSE_GROUP); - sdp_list_t *serviceFilter; - serviceFilter = sdp_list_append(0, &publicBrowseGroupUuid); + if (uuids.empty()) { + fprintf(stderr, "Using PUBLIC_BROWSE_GROUP for SDP search\n"); + uuid_t publicBrowseGroupUuid; + sdp_uuid16_create(&publicBrowseGroupUuid, PUBLIC_BROWSE_GROUP); + uuids.push_back(publicBrowseGroupUuid); + } uint32_t attributeRange = 0x0000ffff; //all attributes sdp_list_t *attributes; attributes = sdp_list_append(0, &attributeRange); - sdp_list_t *sdpResults, *previous; - result = sdp_service_search_attr_req(session, serviceFilter, + sdp_list_t *sdpResults, *sdpIter; + sdp_list_t *totalResults = NULL; + sdp_list_t* serviceFilter; + + for (uint i = 0; i < uuids.size(); ++i) { + serviceFilter = sdp_list_append(0, &uuids[i]); + result = sdp_service_search_attr_req(session, serviceFilter, SDP_ATTR_REQ_RANGE, attributes, &sdpResults); - sdp_list_free(attributes, 0); - sdp_list_free(serviceFilter, 0); + sdp_list_free(serviceFilter, 0); + if (result != 0) { + fprintf(stderr, "sdp_service_search_attr_req failed\n"); + sdp_list_free(attributes, 0); + sdp_close(session); + return RETURN_SDP_ERROR; + } - if (result != 0) { - fprintf(stderr, "sdp_service_search_attr_req failed\n"); - sdp_close(session); - return RETURN_SDP_ERROR; + if (!sdpResults) + continue; + + if (!totalResults) { + totalResults = sdpResults; + sdpIter = totalResults; + } else { + // attach each new result list to the end of totalResults + sdpIter->next = sdpResults; + } + + while (sdpIter->next) // skip to end of list + sdpIter = sdpIter->next; } + sdp_list_free(attributes, 0); + + // start XML generation from the front + sdpResults = totalResults; QByteArray total; while (sdpResults) { @@ -330,9 +404,9 @@ int main(int argc, char **argv) const QByteArray xml = parseSdpRecord(record); total += xml; - previous = sdpResults; + sdpIter = sdpResults; sdpResults = sdpResults->next; - free(previous); + free(sdpIter); sdp_record_free(record); } -- cgit v1.2.3 From 3bf621a5e611eb5b7585464d0453a87b688f7a4e Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Wed, 1 Jun 2016 14:16:23 +0200 Subject: BlueZ5: Prevent premature abortion of device discovery This may happen when the device discovery agent is quickly started and stopped and started again. If the stop-start combination is happening quicker than dbus can deliver the Discovering flag of the Adapter1 BlueZ interface, BlueZ's stop response will override the new start discovery request. Task-number: QTBUG-53715 Change-Id: I6a03fc525c7f390db009fc68a5313352ebba7f79 Reviewed-by: Frank Meerkoetter Reviewed-by: Alex Blasche --- src/bluetooth/bluez/bluez5_helper.cpp | 20 ++++++++++++++++++-- .../qbluetoothdevicediscoveryagent_bluez.cpp | 2 +- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/bluetooth/bluez/bluez5_helper.cpp b/src/bluetooth/bluez/bluez5_helper.cpp index 14e064e1..d77e8fb6 100644 --- a/src/bluetooth/bluez/bluez5_helper.cpp +++ b/src/bluetooth/bluez/bluez5_helper.cpp @@ -260,8 +260,24 @@ void QtBluezDiscoveryManager::PropertiesChanged(const QString &interface, && d->references.contains(propIface->path()) && changed_properties.contains(QStringLiteral("Discovering"))) { bool isDiscovering = changed_properties.value(QStringLiteral("Discovering")).toBool(); - if (!isDiscovering) - removeAdapterFromMonitoring(propIface->path()); + if (!isDiscovering) { + + /* + Once we stop the Discovering flag will switch a few ms later. This comes through this code + path. If a new device discovery is started while we are still + waiting for the flag change signal, then the new device discovery will be aborted prematurely. + To compensate we check whether there was renewed interest. + */ + + AdapterData *data = d->references[propIface->path()]; + if (!data) { + removeAdapterFromMonitoring(propIface->path()); + } else { + OrgBluezAdapter1Interface iface(QStringLiteral("org.bluez"), propIface->path(), + QDBusConnection::systemBus()); + iface.StartDiscovery(); + } + } } } diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp index 7ff57adf..90ad2978 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp @@ -522,7 +522,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_discoveryInterrupted(const QStrin return; if (path == adapterBluez5->path()) { - qCWarning(QT_BT_BLUEZ) << "Device discovery aborted due to unexpected adapter changes"; + qCWarning(QT_BT_BLUEZ) << "Device discovery aborted due to unexpected adapter changes from another process."; if (discoveryTimer) discoveryTimer->stop(); -- cgit v1.2.3 From 74916ede2ff34c2040db9cabbb5a6ee81442a7e8 Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Tue, 31 May 2016 09:43:58 +0200 Subject: Adds a better state transition support to the BluetoothModel When the model changes quickly from one discovery mode to the next, the public device discovery agent and the internal device discovery agent inside QBlutoothServiceDiscoveryAgent interact with each other. One agent is shutting down while the other is starting. Since both instances manage the same hardware, the resulting signals hit the agents in unexpected states which even leads to random crashes. The fix is to let one agent stop and only start the next one once the first has properly shut down. Unfortunately the public BluetoothModel API acts synchronously via its running property. Therefore the synchronous running property must be mapped to asynchronous state changes inside the agents. To achieve this the model uses an internal state transition table which determines how the next setRunning(bool) call is to be processed. As a consequence it is possible to have a non-running BluetoothModel but the internal agent is still shutting down. Another scenario might exhibit a running model whereas one internal agent is still finishing up and the next is waiting to start. Task-number: QTBUG-51307 Change-Id: I0a471b913b8784d2218a797442cee7ee4d00edf3 Reviewed-by: Christian Kandeler Reviewed-by: Timur Pocheptsov Reviewed-by: Oliver Wolff --- .../qdeclarativebluetoothdiscoverymodel.cpp | 245 ++++++++++++++++----- .../qdeclarativebluetoothdiscoverymodel_p.h | 16 ++ 2 files changed, 211 insertions(+), 50 deletions(-) diff --git a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp index c9559296..1f5f5f01 100644 --- a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp +++ b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp @@ -96,7 +96,10 @@ public: m_discoveryMode(QDeclarativeBluetoothDiscoveryModel::MinimalServiceDiscovery), m_running(false), m_runningRequested(true), - m_componentCompleted(false) + m_componentCompleted(false), + m_currentState(QDeclarativeBluetoothDiscoveryModel::IdleAction), + m_nextState(QDeclarativeBluetoothDiscoveryModel::IdleAction), + m_wasDirectDeviceAgentCancel(false) { } ~QDeclarativeBluetoothDiscoveryModelPrivate() @@ -122,12 +125,33 @@ public: bool m_runningRequested; bool m_componentCompleted; QString m_remoteAddress; + + QDeclarativeBluetoothDiscoveryModel::Action m_currentState; + QDeclarativeBluetoothDiscoveryModel::Action m_nextState; + bool m_wasDirectDeviceAgentCancel; }; QDeclarativeBluetoothDiscoveryModel::QDeclarativeBluetoothDiscoveryModel(QObject *parent) : QAbstractListModel(parent), d(new QDeclarativeBluetoothDiscoveryModelPrivate) { + d->m_deviceAgent = new QBluetoothDeviceDiscoveryAgent(this); + connect(d->m_deviceAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)), + this, SLOT(deviceDiscovered(QBluetoothDeviceInfo))); + connect(d->m_deviceAgent, SIGNAL(finished()), this, SLOT(finishedDiscovery())); + connect(d->m_deviceAgent, SIGNAL(canceled()), this, SLOT(finishedDiscovery())); + connect(d->m_deviceAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)), + this, SLOT(errorDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::Error))); + d->m_deviceAgent->setObjectName("DeviceDiscoveryAgent"); + + d->m_serviceAgent = new QBluetoothServiceDiscoveryAgent(this); + connect(d->m_serviceAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)), + this, SLOT(serviceDiscovered(QBluetoothServiceInfo))); + connect(d->m_serviceAgent, SIGNAL(finished()), this, SLOT(finishedDiscovery())); + connect(d->m_serviceAgent, SIGNAL(canceled()), this, SLOT(finishedDiscovery())); + connect(d->m_serviceAgent, SIGNAL(error(QBluetoothServiceDiscoveryAgent::Error)), + this, SLOT(errorDiscovery(QBluetoothServiceDiscoveryAgent::Error))); + d->m_serviceAgent->setObjectName("ServiceDiscoveryAgent"); QHash roleNames; roleNames = QAbstractItemModel::roleNames(); @@ -174,8 +198,8 @@ void QDeclarativeBluetoothDiscoveryModel::errorDeviceDiscovery(QBluetoothDeviceD //QBluetoothDeviceDiscoveryAgent::finished() signal is not emitted in case of an error //Note that this behavior is different from QBluetoothServiceDiscoveryAgent. - //This reset the models running flag. - setRunning(false); + //This resets the models running flag. + finishedDiscovery(); } void QDeclarativeBluetoothDiscoveryModel::clearModel() @@ -331,7 +355,35 @@ void QDeclarativeBluetoothDiscoveryModel::deviceDiscovered(const QBluetoothDevic void QDeclarativeBluetoothDiscoveryModel::finishedDiscovery() { - setRunning(false); + QDeclarativeBluetoothDiscoveryModel::Action previous = d->m_currentState; + d->m_currentState = IdleAction; + + switch (previous) { + case IdleAction: + // last transition didn't even start + // can happen when start() or stop() immediately returned + // usually this happens within a current transitionToNextAction call + break; + case StopAction: + qCDebug(QT_BT_QML) << "Agent cancel detected"; + transitionToNextAction(); + break; + default: // all other + qCDebug(QT_BT_QML) << "Discovery finished" << sender()->objectName(); + + //TODO Qt6 This hack below is once again due to the pendingCancel logic + // because QBluetoothDeviceDiscoveryAgent::isActive() is not reliable. + // In toggleStartStop() we need to know whether the stop() is delayed or immediate. + // isActive() cannot be used. Hence we have to wait for the canceled() signal. + // Android, WinRT and Bluez5 are immediate, Bluez4 is always delayed. + // The immediate case is what we catch here. + if (sender() == d->m_deviceAgent && d->m_nextState == StopAction) { + d->m_wasDirectDeviceAgentCancel = true; + return; + } + setRunning(false); + break; + } } /*! @@ -361,6 +413,131 @@ void QDeclarativeBluetoothDiscoveryModel::setDiscoveryMode(DiscoveryMode discove emit discoveryModeChanged(); } + +void QDeclarativeBluetoothDiscoveryModel::updateNextAction(Action action) +{ + qCDebug(QT_BT_QML) << "New action queue:" + << d->m_currentState << d->m_nextState << action; + + if (action == IdleAction) + return; + + switch (d->m_nextState) { + case IdleAction: + d->m_nextState = action; + return; + case StopAction: + qWarning() << "Invalid Stop state when processing new action" << action; + return; + case DeviceDiscoveryAction: + case MinimalServiceDiscoveryAction: + case FullServiceDiscoveryAction: + if (action == StopAction) // cancel out previous start call + d->m_nextState = IdleAction; + else + qWarning() << "Ignoring new DMF state while another DMF state is scheduled."; + return; + } +} + +void QDeclarativeBluetoothDiscoveryModel::transitionToNextAction() +{ + qCDebug(QT_BT_QML) << "Before transition change:" << d->m_currentState << d->m_nextState; + bool isRunning; + switch (d->m_currentState) { + case IdleAction: + switch (d->m_nextState) { + case IdleAction: break; // nothing to do + case StopAction: d->m_nextState = IdleAction; break; // clear, nothing to do + case DeviceDiscoveryAction: + case MinimalServiceDiscoveryAction: + case FullServiceDiscoveryAction: + Action temp = d->m_nextState; + clearModel(); + isRunning = toggleStartStop(d->m_nextState); + d->m_nextState = IdleAction; + if (isRunning) { + d->m_currentState = temp; + } else { + if (temp != DeviceDiscoveryAction ) + errorDiscovery(d->m_serviceAgent->error()); + d->m_running = false; + } + } + break; + case StopAction: + break; // do nothing, StopAction cleared by finished()/cancelled()/error() handlers + case DeviceDiscoveryAction: + case MinimalServiceDiscoveryAction: + case FullServiceDiscoveryAction: + switch (d->m_nextState) { + case IdleAction: break; + case StopAction: + isRunning = toggleStartStop(StopAction); + (isRunning) ? d->m_currentState = StopAction : d->m_currentState = IdleAction; + d->m_nextState = IdleAction; + break; + default: + Q_ASSERT(false); // should never happen + break; + } + + break; + } + + qCDebug(QT_BT_QML) << "After transition change:" << d->m_currentState << d->m_nextState; +} + +// Returns true if the agent is active +// this can be used to detect whether the agent still needs time to +// perform the requested action. +bool QDeclarativeBluetoothDiscoveryModel::toggleStartStop(Action action) +{ + Q_ASSERT(action != IdleAction); + switch (action) { + case DeviceDiscoveryAction: + Q_ASSERT(!d->m_deviceAgent->isActive() && !d->m_serviceAgent->isActive()); + d->m_deviceAgent->start(); + return d->m_deviceAgent->isActive(); + case MinimalServiceDiscoveryAction: + case FullServiceDiscoveryAction: + Q_ASSERT(!d->m_deviceAgent->isActive() && !d->m_serviceAgent->isActive()); + d->m_serviceAgent->setRemoteAddress(QBluetoothAddress(d->m_remoteAddress)); + d->m_serviceAgent->clear(); + + if (!d->m_uuid.isEmpty()) + d->m_serviceAgent->setUuidFilter(QBluetoothUuid(d->m_uuid)); + + if (action == FullServiceDiscoveryAction) { + qCDebug(QT_BT_QML) << "Full Discovery"; + d->m_serviceAgent->start(QBluetoothServiceDiscoveryAgent::FullDiscovery); + } else { + qCDebug(QT_BT_QML) << "Minimal Discovery"; + d->m_serviceAgent->start(QBluetoothServiceDiscoveryAgent::MinimalDiscovery); + } + return d->m_serviceAgent->isActive(); + case StopAction: + Q_ASSERT(d->m_currentState != StopAction && d->m_currentState != IdleAction); + if (d->m_currentState == DeviceDiscoveryAction) { + d->m_deviceAgent->stop(); + + // TODO Qt6 Crude hack below + // cannot use isActive() below due to pendingCancel logic + // we always wait for canceled() signal coming through or check + // for directly invoked cancel() response caused by stop() above + bool stillActive = !d->m_wasDirectDeviceAgentCancel; + d->m_wasDirectDeviceAgentCancel = false; + return stillActive; + } else { + d->m_serviceAgent->stop(); + return d->m_serviceAgent->isActive(); + } + default: + return true; + } +} + + /*! \qmlproperty bool BluetoothDiscoveryModel::running @@ -386,55 +563,23 @@ void QDeclarativeBluetoothDiscoveryModel::setRunning(bool running) d->m_running = running; - if (!running) { - if (d->m_deviceAgent) - d->m_deviceAgent->stop(); - if (d->m_serviceAgent) - d->m_serviceAgent->stop(); + Action nextAction = IdleAction; + if (running) { + if (discoveryMode() == MinimalServiceDiscovery) + nextAction = MinimalServiceDiscoveryAction; + else if (discoveryMode() == FullServiceDiscovery) + nextAction = FullServiceDiscoveryAction; + else + nextAction = DeviceDiscoveryAction; } else { - clearModel(); - d->m_error = NoError; - if (d->m_discoveryMode == DeviceDiscovery) { - if (!d->m_deviceAgent) { - d->m_deviceAgent = new QBluetoothDeviceDiscoveryAgent(this); - connect(d->m_deviceAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)), this, SLOT(deviceDiscovered(QBluetoothDeviceInfo))); - connect(d->m_deviceAgent, SIGNAL(finished()), this, SLOT(finishedDiscovery())); - connect(d->m_deviceAgent, SIGNAL(canceled()), this, SLOT(finishedDiscovery())); - connect(d->m_deviceAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)), this, SLOT(errorDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::Error))); - } - d->m_deviceAgent->start(); - } else { - if (!d->m_serviceAgent) { - d->m_serviceAgent = new QBluetoothServiceDiscoveryAgent(this); - connect(d->m_serviceAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)), this, SLOT(serviceDiscovered(QBluetoothServiceInfo))); - connect(d->m_serviceAgent, SIGNAL(finished()), this, SLOT(finishedDiscovery())); - connect(d->m_serviceAgent, SIGNAL(canceled()), this, SLOT(finishedDiscovery())); - connect(d->m_serviceAgent, SIGNAL(error(QBluetoothServiceDiscoveryAgent::Error)), this, SLOT(errorDiscovery(QBluetoothServiceDiscoveryAgent::Error))); - } - - d->m_serviceAgent->setRemoteAddress(QBluetoothAddress(d->m_remoteAddress)); - d->m_serviceAgent->clear(); - - if (!d->m_uuid.isEmpty()) - d->m_serviceAgent->setUuidFilter(QBluetoothUuid(d->m_uuid)); - - if (discoveryMode() == FullServiceDiscovery) { - //qDebug() << "Full Discovery"; - d->m_serviceAgent->start(QBluetoothServiceDiscoveryAgent::FullDiscovery); - } else { - //qDebug() << "Minimal Discovery"; - d->m_serviceAgent->start(QBluetoothServiceDiscoveryAgent::MinimalDiscovery); - } - - // we could not start service discovery - if (!d->m_serviceAgent->isActive()) { - d->m_running = false; - errorDiscovery(d->m_serviceAgent->error()); - return; - } - } + nextAction = StopAction; } + Q_ASSERT(nextAction != IdleAction); + updateNextAction(nextAction); + transitionToNextAction(); + + qCDebug(QT_BT_QML) << "Running state:" << d->m_running; emit runningChanged(); } diff --git a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h index a06d49c4..cebff1f2 100644 --- a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h +++ b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h @@ -111,6 +111,8 @@ public: DiscoveryMode discoveryMode() const; void setDiscoveryMode(DiscoveryMode discovery); + // TODO Qt 6 This property behaves synchronously but should really be + // asynchronous. The agents start/stop/restart is not immediate. bool running() const; void setRunning(bool running); @@ -139,8 +141,22 @@ private slots: private: void clearModel(); + enum Action { + IdleAction = 0, + StopAction, + DeviceDiscoveryAction, + MinimalServiceDiscoveryAction, + FullServiceDiscoveryAction + }; + + bool toggleStartStop(Action action); + void updateNextAction(Action action); + void transitionToNextAction(); + private: QDeclarativeBluetoothDiscoveryModelPrivate* d; + friend class QDeclarativeBluetoothDiscoveryModelPrivate; + }; #endif // QDECLARATIVECONTACTMODEL_P_H -- cgit v1.2.3