summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@theqtcompany.com>2016-06-09 15:51:18 +0200
committerAlex Blasche <alexander.blasche@theqtcompany.com>2016-06-09 15:51:25 +0200
commitdb55878a269450d7a8f559e5d3862403eba7fbc8 (patch)
treeea85b2e66fd884e2e142d5be90d0b960eb6b0b98
parent23639ab07278ecae1b12f49da1cee2460c80f335 (diff)
parent6d9a7006e81fc9ef6140bfc62696d1b270aaae08 (diff)
Merge remote-tracking branch 'gerrit/5.7' into dev
-rw-r--r--.qmake.conf1
-rw-r--r--examples/nfc/poster/doc/images/qml-poster-example.pngbin5110 -> 7946 bytes
-rw-r--r--examples/nfc/poster/doc/src/poster.qdoc21
-rw-r--r--examples/nfc/poster/poster.qml14
-rw-r--r--src/bluetooth/bluez/bluez5_helper.cpp20
-rw-r--r--src/bluetooth/doc/src/bluetooth-index.qdoc13
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp2
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp21
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent.cpp8
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_android.cpp6
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp16
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_osx.mm16
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_p.cpp12
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_p.h3
-rw-r--r--src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp245
-rw-r--r--src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h16
-rw-r--r--src/nfc/qnearfieldtagtype1.cpp9
-rw-r--r--src/tools/sdpscanner/main.cpp106
18 files changed, 431 insertions, 98 deletions
diff --git a/.qmake.conf b/.qmake.conf
index aa9ded07..aefa1e70 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,4 +1,3 @@
load(qt_build_config)
-CONFIG += qt_example_installs
MODULE_VERSION = 5.8.0
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
--- a/examples/nfc/poster/doc/images/qml-poster-example.png
+++ b/examples/nfc/poster/doc/images/qml-poster-example.png
Binary files 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 {
diff --git a/src/bluetooth/bluez/bluez5_helper.cpp b/src/bluetooth/bluez/bluez5_helper.cpp
index 2d431367..8871a872 100644
--- a/src/bluetooth/bluez/bluez5_helper.cpp
+++ b/src/bluetooth/bluez/bluez5_helper.cpp
@@ -266,8 +266,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/doc/src/bluetooth-index.qdoc b/src/bluetooth/doc/src/bluetooth-index.qdoc
index 8ea4c7f9..51c79ca4 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}
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp
index b1cbdae5..5f163dfd 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp
@@ -264,6 +264,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startLowEnergyScan()
env->ExceptionClear();
m_active = NoScanActive;
emit q->finished();
+ return;
}
leScanner.setField<jlong>("qtObject", reinterpret_cast<long>(receiver));
@@ -274,6 +275,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startLowEnergyScan()
qCWarning(QT_BT_ANDROID) << "Cannot start BTLE device scanner";
m_active = NoScanActive;
emit q->finished();
+ return;
}
if (!leScanTimeout) {
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp
index 165e7603..0243d31f 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp
@@ -98,12 +98,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);
}
@@ -201,8 +208,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;
}
}
@@ -421,8 +428,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;
@@ -431,6 +438,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
@@ -498,8 +509,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;
@@ -517,7 +528,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();
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.cpp b/src/bluetooth/qbluetoothservicediscoveryagent.cpp
index fa1aba9d..cd28cc25 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent.cpp
@@ -149,9 +149,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;
}
/*!
@@ -167,9 +167,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<QBluetoothHostInfo> localDevices = QBluetoothLocalDevice::allDevices();
foreach (const QBluetoothHostInfo &hostInfo, localDevices) {
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp
index 478efd93..ba5bcb0a 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp
@@ -54,11 +54,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<QBluetoothHostInfo> 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 e9c3d1b1..672dcf0d 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp
@@ -68,10 +68,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(
@@ -218,15 +220,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/bluetooth/qbluetoothservicediscoveryagent_osx.mm b/src/bluetooth/qbluetoothservicediscoveryagent_osx.mm
index 51b892e6..dc9d4ee9 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_osx.mm
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_osx.mm
@@ -68,7 +68,8 @@ public:
ServiceDiscovery,
};
- QBluetoothServiceDiscoveryAgentPrivate(const QBluetoothAddress &localAddress);
+ QBluetoothServiceDiscoveryAgentPrivate(QBluetoothServiceDiscoveryAgent *qp,
+ const QBluetoothAddress &localAddress);
void startDeviceDiscovery();
void stopDeviceDiscovery();
@@ -116,8 +117,9 @@ private:
OSXBluetooth::ObjCScopedPointer<ObjCServiceInquiry> 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),
@@ -429,15 +431,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<QBluetoothHostInfo> localDevices = QBluetoothLocalDevice::allDevices();
foreach (const QBluetoothHostInfo &hostInfo, localDevices) {
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_p.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_p.cpp
index c7780e7f..948fdf3e 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_p.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_p.cpp
@@ -45,10 +45,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 42bb5598..47231d8f 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_p.h
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_p.h
@@ -93,7 +93,8 @@ public:
ServiceDiscovery,
};
- QBluetoothServiceDiscoveryAgentPrivate(const QBluetoothAddress &deviceAdapter);
+ QBluetoothServiceDiscoveryAgentPrivate(QBluetoothServiceDiscoveryAgent *qp,
+ const QBluetoothAddress &deviceAdapter);
~QBluetoothServiceDiscoveryAgentPrivate();
void startDeviceDiscovery();
diff --git a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp
index 9521e3b8..f2486e81 100644
--- a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp
+++ b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp
@@ -102,7 +102,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()
@@ -128,12 +131,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<int, QByteArray> roleNames;
roleNames = QAbstractItemModel::roleNames();
@@ -180,8 +204,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()
@@ -337,7 +361,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;
+ }
}
/*!
@@ -367,6 +419,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
@@ -392,55 +569,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 ff6725d3..a3cfdcf2 100644
--- a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h
+++ b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h
@@ -117,6 +117,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);
@@ -145,8 +147,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
diff --git a/src/nfc/qnearfieldtagtype1.cpp b/src/nfc/qnearfieldtagtype1.cpp
index f365b1a3..5d46b8c5 100644
--- a/src/nfc/qnearfieldtagtype1.cpp
+++ b/src/nfc/qnearfieldtagtype1.cpp
@@ -82,7 +82,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;
@@ -170,11 +171,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;
@@ -246,11 +249,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;
@@ -270,6 +275,7 @@ void QNearFieldTagType1Private::progressToNextNdefWriteMessageState()
// fall through
case NdefWriteWritingTlv:
+ delete m_tlvWriter;
m_tlvWriter = new QTlvWriter(q);
// write old TLVs
@@ -288,6 +294,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;
diff --git a/src/tools/sdpscanner/main.cpp b/src/tools/sdpscanner/main.cpp
index bf978c0d..edca8fa3 100644
--- a/src/tools/sdpscanner/main.cpp
+++ b/src/tools/sdpscanner/main.cpp
@@ -40,6 +40,7 @@
#include <QtCore/QByteArray>
#include <QtCore/QDebug>
#include <stdio.h>
+#include <string>
#include <bluetooth/bluetooth.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
@@ -52,11 +53,14 @@
void usage()
{
fprintf(stderr, "Usage:\n");
- fprintf(stderr, "\tsdpscanner <remote bdaddr> <local bdaddr> [Options]\n\n");
+ fprintf(stderr, "\tsdpscanner <remote bdaddr> <local bdaddr> [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
@@ -275,6 +279,7 @@ int main(int argc, char **argv)
}
bool showHumanReadable = false;
+ std::vector<std::string> targetServices;
for (int i = 3; i < argc; i++) {
if (argv[i][0] != '-') {
@@ -287,12 +292,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<uuid_t> uuids;
+ for (std::vector<std::string>::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);
@@ -307,27 +356,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) {
@@ -336,9 +410,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);
}