diff options
author | Juha Vuolle <juha.vuolle@insta.fi> | 2022-06-23 15:34:22 +0300 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2022-06-28 11:44:59 +0000 |
commit | cbd5f6c09a441dfd47a114eb742ee97d56642e0e (patch) | |
tree | db6a7cc10e36432c9cef69f379af9af8505970c0 | |
parent | 84530d293f98b7f8694a27e4de5bd2875719107a (diff) | |
download | qtconnectivity-cbd5f6c09a441dfd47a114eb742ee97d56642e0e.tar.gz |
Fix bluetooth service discovery not finishing on Android
The service discovery finished signal is not emitted when
the SDP cache is empty when last device inquiry of services finishes.
This commit changes the logic so that the the inquiry is finished
independent of whether actual services were discovered on (any) of
the devices.
As a related drive-by:
- Document the role of sdpCache to ease understanding
- Change raw timeout limits into a variable
Fixes: QTBUG-104479
Change-Id: Ifc9e8587a66769a1fc7959a8154f2be72ffd7461
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
(cherry picked from commit 7c7d860ca52dc19e994a1166b6e2d0f5fa869455)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | src/bluetooth/qbluetoothservicediscoveryagent_android.cpp | 26 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothservicediscoveryagent_p.h | 6 |
2 files changed, 22 insertions, 10 deletions
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp index 6f2b84cc..58deb341 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp @@ -20,6 +20,8 @@ QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID) +static constexpr auto uuidFetchTimeLimit = std::chrono::seconds{4}; + QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate( QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &deviceAdapter) : error(QBluetoothServiceDiscoveryAgent::NoError), @@ -216,7 +218,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_processFetchedUuids( if (address.isNull() || uuids.isEmpty()) { if (discoveredDevices.size() == 1) { Q_Q(QBluetoothServiceDiscoveryAgent); - QTimer::singleShot(4000, q, [this]() { + QTimer::singleShot(uuidFetchTimeLimit, q, [this]() { this->_q_fetchUuidsTimeout(); }); // will also call _q_serviceDiscoveryFinished() } else { @@ -235,7 +237,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_processFetchedUuids( qCDebug(QT_BT_ANDROID) << result; } - /* In general there are two uuid events per device. + /* In general there may be up-to two uuid events per device. * We'll wait for the second event to arrive before we process the UUIDs. * We utilize a timeout to catch cases when the second * event doesn't arrive at all. @@ -266,10 +268,10 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_processFetchedUuids( sdpCache.insert(address, pair); //the discovery on the last device cannot immediately finish - //we have to grant the 2 seconds timeout delay + //we have to grant the timeout delay to allow potential second event to arrive if (discoveredDevices.size() == 1) { Q_Q(QBluetoothServiceDiscoveryAgent); - QTimer::singleShot(4000, q, [this]() { + QTimer::singleShot(uuidFetchTimeLimit, q, [this]() { this->_q_fetchUuidsTimeout(); }); return; @@ -422,14 +424,18 @@ void QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices(const QB void QBluetoothServiceDiscoveryAgentPrivate::_q_fetchUuidsTimeout() { - if (sdpCache.isEmpty()) + // In practice if device list is empty, discovery has been stopped or bluetooth is offline + if (discoveredDevices.isEmpty()) return; - QPair<QBluetoothDeviceInfo,QList<QBluetoothUuid> > pair; - const QList<QBluetoothAddress> keys = sdpCache.keys(); - for (const QBluetoothAddress &key : keys) { - pair = sdpCache.take(key); - populateDiscoveredServices(pair.first, pair.second); + // Process remaining services in the cache (these didn't get a second UUID event) + if (!sdpCache.isEmpty()) { + QPair<QBluetoothDeviceInfo,QList<QBluetoothUuid> > pair; + const QList<QBluetoothAddress> keys = sdpCache.keys(); + for (const QBluetoothAddress &key : keys) { + pair = sdpCache.take(key); + populateDiscoveredServices(pair.first, pair.second); + } } Q_ASSERT(sdpCache.isEmpty()); diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_p.h b/src/bluetooth/qbluetoothservicediscoveryagent_p.h index ee18754b..b7f04b11 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_p.h +++ b/src/bluetooth/qbluetoothservicediscoveryagent_p.h @@ -156,6 +156,12 @@ private: LocalDeviceBroadcastReceiver *localDeviceReceiver = nullptr; QJniObject btAdapter; + // The sdpCache caches service discovery results while it is running, and is + // cleared once finished. The cache is used as we may (or may not) get more accurate + // results after the first result. This temporary caching allows to send the + // serviceDiscovered() signal once per service and with the most accurate information. + // Partial cache clearing may occur already during the scan if the second (more accurate) + // scan result is received. QMap<QBluetoothAddress,QPair<QBluetoothDeviceInfo,QList<QBluetoothUuid> > > sdpCache; #endif |