diff options
author | Alex Blasche <alexander.blasche@theqtcompany.com> | 2016-06-09 15:00:36 +0200 |
---|---|---|
committer | Alex Blasche <alexander.blasche@theqtcompany.com> | 2016-06-09 15:00:43 +0200 |
commit | 6d9a7006e81fc9ef6140bfc62696d1b270aaae08 (patch) | |
tree | d7ce8d417f32ab73543740beab3cdee36b4fdfaf /src/imports | |
parent | bde54c522b76eeb933296aa1a9e159facbf8e529 (diff) | |
parent | 74916ede2ff34c2040db9cabbb5a6ee81442a7e8 (diff) |
Merge remote-tracking branch 'gerrit/5.6' into 5.7
Change-Id: Id8dffff9bb75db396aabf6da2a3acb78505a6476
Diffstat (limited to 'src/imports')
-rw-r--r-- | src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp | 245 | ||||
-rw-r--r-- | src/imports/bluetooth/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 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 |