summaryrefslogtreecommitdiffstats
path: root/src/imports
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@theqtcompany.com>2016-06-09 15:00:36 +0200
committerAlex Blasche <alexander.blasche@theqtcompany.com>2016-06-09 15:00:43 +0200
commit6d9a7006e81fc9ef6140bfc62696d1b270aaae08 (patch)
treed7ce8d417f32ab73543740beab3cdee36b4fdfaf /src/imports
parentbde54c522b76eeb933296aa1a9e159facbf8e529 (diff)
parent74916ede2ff34c2040db9cabbb5a6ee81442a7e8 (diff)
Merge remote-tracking branch 'gerrit/5.6' into 5.7
Diffstat (limited to 'src/imports')
-rw-r--r--src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp245
-rw-r--r--src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h16
2 files changed, 211 insertions, 50 deletions
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