summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuha Vuolle <juha.vuolle@insta.fi>2022-06-23 15:34:22 +0300
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2022-06-28 11:44:59 +0000
commitcbd5f6c09a441dfd47a114eb742ee97d56642e0e (patch)
treedb6a7cc10e36432c9cef69f379af9af8505970c0
parent84530d293f98b7f8694a27e4de5bd2875719107a (diff)
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.cpp26
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_p.h6
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