diff options
Diffstat (limited to 'src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp')
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp | 173 |
1 files changed, 115 insertions, 58 deletions
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp index a7def3d0..7dce9dae 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp @@ -135,6 +135,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent } discoveredDevices.clear(); + devicesProperties.clear(); if (managerBluez5) { startBluez5(methods); @@ -309,7 +310,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startBluez5(QBluetoothDeviceDiscover if (path.path().indexOf(adapterBluez5->path()) != 0) continue; //devices whose path doesn't start with same path we skip - deviceFoundBluez5(path.path()); + deviceFoundBluez5(path.path(), jt.value()); if (!isActive()) // Can happen if stop() was called from a slot in user code. return; } @@ -403,50 +404,23 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_deviceFound(const QString &addres emit q->deviceDiscovered(device); } -void QBluetoothDeviceDiscoveryAgentPrivate::deviceFoundBluez5(const QString& devicePath) +// Returns invalid QBluetoothDeviceInfo in case of error +static QBluetoothDeviceInfo createDeviceInfoFromBluez5Device(const QVariantMap& properties) { - Q_Q(QBluetoothDeviceDiscoveryAgent); - - if (!q->isActive()) - return; - - OrgBluezDevice1Interface device(QStringLiteral("org.bluez"), devicePath, - QDBusConnection::systemBus()); - - if (device.adapter().path() != adapterBluez5->path()) - return; - - const QBluetoothAddress btAddress(device.address()); - if (btAddress.isNull()) // no point reporting an empty address - return; + const QBluetoothAddress btAddress(properties[QStringLiteral("Address")].toString()); + if (btAddress.isNull()) + return QBluetoothDeviceInfo(); - const QString btName = device.alias(); - quint32 btClass = device.classProperty(); + const QString btName = properties[QStringLiteral("Alias")].toString(); + quint32 btClass = properties[QStringLiteral("Class")].toUInt(); - qCDebug(QT_BT_BLUEZ) << "Discovered: " << btAddress.toString() << btName - << "Num UUIDs" << device.uUIDs().count() - << "total device" << discoveredDevices.count() << "cached" - << "RSSI" << device.rSSI() << "Class" << btClass - << "Num ManufacturerData" << device.manufacturerData().size(); - - OrgFreedesktopDBusPropertiesInterface *prop = new OrgFreedesktopDBusPropertiesInterface( - QStringLiteral("org.bluez"), devicePath, QDBusConnection::systemBus(), q); - QObject::connect(prop, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged, - q, [this](const QString &interface, const QVariantMap &changedProperties, - const QStringList &invalidatedProperties) { - this->_q_PropertiesChanged(interface, changedProperties, invalidatedProperties); - }); - - // remember what we have to cleanup - propertyMonitors.append(prop); - - // read information QBluetoothDeviceInfo deviceInfo(btAddress, btName, btClass); - deviceInfo.setRssi(device.rSSI()); + deviceInfo.setRssi(qvariant_cast<short>(properties[QStringLiteral("RSSI")])); QVector<QBluetoothUuid> uuids; bool foundLikelyLowEnergyUuid = false; - for (const auto &u: device.uUIDs()) { + const QStringList foundUuids = qvariant_cast<QStringList>(properties[QStringLiteral("UUIDs")]); + for (const auto &u: foundUuids) { const QBluetoothUuid id(u); if (id.isNull()) continue; @@ -470,16 +444,56 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFoundBluez5(const QString& dev deviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration); } - const ManufacturerDataList deviceManufacturerData = device.manufacturerData(); + const ManufacturerDataList deviceManufacturerData = qdbus_cast<ManufacturerDataList>(properties[QStringLiteral("ManufacturerData")]); const QList<quint16> keys = deviceManufacturerData.keys(); for (quint16 key : keys) deviceInfo.setManufacturerData( key, deviceManufacturerData.value(key).variant().toByteArray()); + return deviceInfo; +} + +void QBluetoothDeviceDiscoveryAgentPrivate::deviceFoundBluez5(const QString &devicePath, + const QVariantMap &properties) +{ + Q_Q(QBluetoothDeviceDiscoveryAgent); + + if (!q->isActive()) + return; + + auto deviceAdapter = qvariant_cast<QDBusObjectPath>(properties[QStringLiteral("Adapter")]); + if (deviceAdapter.path() != adapterBluez5->path()) + return; + + // read information + QBluetoothDeviceInfo deviceInfo = createDeviceInfoFromBluez5Device(properties); + if (!deviceInfo.isValid()) // no point reporting an empty address + return; + + qCDebug(QT_BT_BLUEZ) << "Discovered: " << deviceInfo.name() << deviceInfo.address() + << "Num UUIDs" << deviceInfo.serviceUuids().count() + << "total device" << discoveredDevices.count() << "cached" + << "RSSI" << deviceInfo.rssi() + << "Num ManufacturerData" << deviceInfo.manufacturerData().size(); + + OrgFreedesktopDBusPropertiesInterface *prop = new OrgFreedesktopDBusPropertiesInterface( + QStringLiteral("org.bluez"), devicePath, QDBusConnection::systemBus(), q); + QObject::connect(prop, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged, + q, [this](const QString &interface, const QVariantMap &changedProperties, + const QStringList &invalidatedProperties) { + this->_q_PropertiesChanged(interface, changedProperties, invalidatedProperties); + }); + + // remember what we have to cleanup + propertyMonitors.append(prop); + + // Cache the properties so we do not have to access dbus every time to get a value + devicesProperties[devicePath] = properties; + for (int i = 0; i < discoveredDevices.size(); i++) { if (discoveredDevices[i].address() == deviceInfo.address()) { - if (discoveredDevices[i] == deviceInfo && lowEnergySearchTimeout > 0) { - qCDebug(QT_BT_BLUEZ) << "Duplicate: " << btAddress.toString(); + if (lowEnergySearchTimeout > 0 && discoveredDevices[i] == deviceInfo) { + qCDebug(QT_BT_BLUEZ) << "Duplicate: " << deviceInfo.address(); return; } discoveredDevices.replace(i, deviceInfo); @@ -567,7 +581,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_InterfacesAdded(const QDBusObject if (interfaces_and_properties.contains(QStringLiteral("org.bluez.Device1"))) { // device interfaces belonging to different adapter // will be filtered out by deviceFoundBluez5(); - deviceFoundBluez5(object_path.path()); + deviceFoundBluez5(object_path.path(), interfaces_and_properties[QStringLiteral("org.bluez.Device1")]); } } @@ -628,40 +642,84 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_discoveryInterrupted(const QStrin void QBluetoothDeviceDiscoveryAgentPrivate::_q_PropertiesChanged(const QString &interface, const QVariantMap &changed_properties, - const QStringList &) + const QStringList &invalidated_properties) { Q_Q(QBluetoothDeviceDiscoveryAgent); - if (interface == QStringLiteral("org.bluez.Device1") - && (changed_properties.contains(QStringLiteral("RSSI")) - || changed_properties.contains(QStringLiteral("ManufacturerData")))) { - OrgFreedesktopDBusPropertiesInterface *props = - qobject_cast<OrgFreedesktopDBusPropertiesInterface *>(q->sender()); - if (!props) - return; + if (interface != QStringLiteral("org.bluez.Device1")) + return; + + OrgFreedesktopDBusPropertiesInterface *props = + qobject_cast<OrgFreedesktopDBusPropertiesInterface *>(q->sender()); + if (!props) + return; + + const QString path = props->path(); + if (!devicesProperties.contains(path)) + return; + + // Update the cached properties before checking changed_properties for RSSI and ManufacturerData + // so the cached properties are always up to date. + QVariantMap & properties = devicesProperties[path]; + for (QVariantMap::const_iterator it = changed_properties.constBegin(); + it != changed_properties.constEnd(); ++it) { + properties[it.key()] = it.value(); + } + + for (const QString & property : invalidated_properties) + properties.remove(property); + + const auto info = createDeviceInfoFromBluez5Device(properties); + if (!info.isValid()) + return; + + if (changed_properties.contains(QStringLiteral("RSSI")) + || changed_properties.contains(QStringLiteral("ManufacturerData"))) { - OrgBluezDevice1Interface device(QStringLiteral("org.bluez"), props->path(), - QDBusConnection::systemBus()); for (int i = 0; i < discoveredDevices.size(); i++) { - if (discoveredDevices[i].address().toString() == device.address()) { + if (discoveredDevices[i].address() == info.address()) { QBluetoothDeviceInfo::Fields updatedFields = QBluetoothDeviceInfo::Field::None; if (changed_properties.contains(QStringLiteral("RSSI"))) { - qCDebug(QT_BT_BLUEZ) << "Updating RSSI for" << device.address() + qCDebug(QT_BT_BLUEZ) << "Updating RSSI for" << info.address() << changed_properties.value(QStringLiteral("RSSI")); discoveredDevices[i].setRssi( changed_properties.value(QStringLiteral("RSSI")).toInt()); updatedFields.setFlag(QBluetoothDeviceInfo::Field::RSSI); } if (changed_properties.contains(QStringLiteral("ManufacturerData"))) { - qCDebug(QT_BT_BLUEZ) << "Updating ManufacturerData for" << device.address(); + qCDebug(QT_BT_BLUEZ) << "Updating ManufacturerData for" << info.address(); ManufacturerDataList changedManufacturerData = qdbus_cast< ManufacturerDataList >(changed_properties.value(QStringLiteral("ManufacturerData"))); const QList<quint16> keys = changedManufacturerData.keys(); + bool wasNewValue = false; for (quint16 key : keys) { - if (discoveredDevices[i].setManufacturerData(key, changedManufacturerData.value(key).variant().toByteArray())) - updatedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData); + bool added = discoveredDevices[i].setManufacturerData(key, changedManufacturerData.value(key).variant().toByteArray()); + wasNewValue = (wasNewValue || added); } + + if (wasNewValue) + updatedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData); } + + if (lowEnergySearchTimeout > 0) { + if (discoveredDevices[i] != info) { // field other than manufacturer or rssi changed + if (discoveredDevices.at(i).name() == info.name()) { + qCDebug(QT_BT_BLUEZ) << "Almost Duplicate " << info.address() + << info.name() << "- replacing in place"; + discoveredDevices.replace(i, info); + emit q->deviceDiscovered(info); + } + } else { + if (!updatedFields.testFlag(QBluetoothDeviceInfo::Field::None)) + emit q->deviceUpdated(discoveredDevices[i], updatedFields); + } + + return; + } + + discoveredDevices.replace(i, info); + emit q_ptr->deviceDiscovered(discoveredDevices[i]); + if (!updatedFields.testFlag(QBluetoothDeviceInfo::Field::None)) emit q->deviceUpdated(discoveredDevices[i], updatedFields); return; @@ -669,5 +727,4 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_PropertiesChanged(const QString & } } } - QT_END_NAMESPACE |