summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/bluetooth/qbluetoothservicediscoveryagent_android.cpp')
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_android.cpp133
1 files changed, 81 insertions, 52 deletions
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp
index ce2911d3..3ab0d580 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp
@@ -47,6 +47,7 @@
#include <QtBluetooth/QBluetoothServiceDiscoveryAgent>
#include "qbluetoothservicediscoveryagent_p.h"
+#include "qbluetoothsocket_android_p.h"
#include "android/servicediscoverybroadcastreceiver_p.h"
#include "android/localdevicebroadcastreceiver_p.h"
@@ -55,21 +56,33 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(
- QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &/*deviceAdapter*/)
+ QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &deviceAdapter)
: error(QBluetoothServiceDiscoveryAgent::NoError),
+ m_deviceAdapterAddress(deviceAdapter),
state(Inactive),
mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery),
singleDevice(false),
q_ptr(qp)
{
- QList<QBluetoothHostInfo> devices = QBluetoothLocalDevice::allDevices();
- Q_ASSERT(devices.count() <= 1); //Android only supports one device at the moment
-
- if (devices.isEmpty()) {
- error = QBluetoothServiceDiscoveryAgent::InvalidBluetoothAdapterError;
- errorString = QBluetoothServiceDiscoveryAgent::tr("Invalid Bluetooth adapter address");
- return;
+ // If a specific adapter address is requested we need to check it matches
+ // the current local adapter. If it does not match we emit
+ // InvalidBluetoothAdapterError when calling start()
+
+ bool createAdapter = true;
+ if (!deviceAdapter.isNull()) {
+ const QList<QBluetoothHostInfo> devices = QBluetoothLocalDevice::allDevices();
+ if (devices.isEmpty()) {
+ createAdapter = false;
+ } else {
+ auto match = [deviceAdapter](const QBluetoothHostInfo& info) {
+ return info.address() == deviceAdapter;
+ };
+
+ auto result = std::find_if(devices.begin(), devices.end(), match);
+ if (result == devices.end())
+ createAdapter = false;
+ }
}
if (QtAndroidPrivate::androidSdkVersion() < 15)
@@ -84,7 +97,8 @@ QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(
The logic below must change once there is more than one adapter.
*/
- btAdapter = QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter",
+ if (createAdapter)
+ btAdapter = QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter",
"getDefaultAdapter",
"()Landroid/bluetooth/BluetoothAdapter;");
if (!btAdapter.isValid())
@@ -110,8 +124,15 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr
Q_Q(QBluetoothServiceDiscoveryAgent);
if (!btAdapter.isValid()) {
- error = QBluetoothServiceDiscoveryAgent::UnknownError;
- errorString = QBluetoothServiceDiscoveryAgent::tr("Platform does not support Bluetooth");
+ if (m_deviceAdapterAddress.isNull()) {
+ error = QBluetoothServiceDiscoveryAgent::UnknownError;
+ errorString = QBluetoothServiceDiscoveryAgent::tr("Platform does not support Bluetooth");
+ } else {
+ // specific adapter was requested which does not match the locally
+ // existing adapter
+ error = QBluetoothServiceDiscoveryAgent::InvalidBluetoothAdapterError;
+ errorString = QBluetoothServiceDiscoveryAgent::tr("Invalid Bluetooth adapter address");
+ }
//abort any outstanding discoveries
discoveredDevices.clear();
@@ -315,42 +336,62 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_processFetchedUuids(
void QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices(const QBluetoothDeviceInfo &remoteDevice, const QList<QBluetoothUuid> &uuids)
{
- /* Android doesn't provide decent SDP data. A list of uuids is close to meaning-less
+ /* Android doesn't provide decent SDP data. A flat list of uuids is all we get.
*
* The following approach is chosen:
* - If we see an SPP service class and we see
- * one or more custom uuids we match them up. Such services will always be SPP services.
+ * one or more custom uuids we match them up. Such services will always
+ * be SPP services. There is the chance that a custom uuid is eronously
+ * mapped as being an SPP service. In addition, the SPP uuid will be mapped as
+ * standalone SPP service.
* - If we see a custom uuid but no SPP uuid then we return
- * BluetoothServiceInfo instance with just a servuceUuid (no service class set)
+ * BluetoothServiceInfo instance with just a serviceUuid (no service class set)
+ * - If we don't find any custom uuid but the SPP uuid, we return a
+ * BluetoothServiceInfo instance where classId and serviceUuid() are set to SPP.
* - Any other service uuid will stand on its own.
* */
Q_Q(QBluetoothServiceDiscoveryAgent);
//find SPP and custom uuid
- QBluetoothUuid uuid;
- int sppIndex = -1;
+ bool haveSppClass = false;
QVector<int> customUuids;
for (int i = 0; i < uuids.count(); i++) {
- uuid = uuids.at(i);
+ const QBluetoothUuid uuid = uuids.at(i);
if (uuid.isNull())
continue;
//check for SPP protocol
bool ok = false;
- quint16 uuid16 = uuid.toUInt16(&ok);
- if (ok && uuid16 == QBluetoothUuid::SerialPort)
- sppIndex = i;
+ auto uuid16 = uuid.toUInt16(&ok);
+ haveSppClass |= ok && uuid16 == QBluetoothUuid::SerialPort;
//check for custom uuid
if (uuid.minimumSize() == 16)
customUuids.append(i);
}
+ auto rfcommProtocolDescriptorList = []() -> QBluetoothServiceInfo::Sequence {
+ QBluetoothServiceInfo::Sequence protocol;
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
+ << QVariant::fromValue(0);
+ return protocol;
+ };
+
+ auto sppProfileDescriptorList = []() -> QBluetoothServiceInfo::Sequence {
+ QBluetoothServiceInfo::Sequence profileSequence;
+ QBluetoothServiceInfo::Sequence classId;
+ classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
+ classId << QVariant::fromValue(quint16(0x100));
+ profileSequence.append(QVariant::fromValue(classId));
+ return profileSequence;
+ };
+
for (int i = 0; i < uuids.count(); i++) {
- if (i == sppIndex && !customUuids.isEmpty())
+ const QBluetoothUuid &uuid = uuids.at(i);
+ if (uuid.isNull())
continue;
QBluetoothServiceInfo serviceInfo;
@@ -363,52 +404,38 @@ void QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices(const QB
protocolDescriptorList.append(QVariant::fromValue(protocol));
}
- if (customUuids.contains(i) && sppIndex > -1) {
+ if (customUuids.contains(i) && haveSppClass) {
//we have a custom uuid of service class type SPP
//set rfcomm protocol
- QBluetoothServiceInfo::Sequence protocol;
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
- << QVariant::fromValue(0);
- protocolDescriptorList.append(QVariant::fromValue(protocol));
+ protocolDescriptorList.append(QVariant::fromValue(rfcommProtocolDescriptorList()));
- QBluetoothServiceInfo::Sequence profileSequence;
- QBluetoothServiceInfo::Sequence classId;
- classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
- classId << QVariant::fromValue(quint16(0x100));
- profileSequence.append(QVariant::fromValue(classId));
+ //set SPP profile descriptor list
serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList,
- profileSequence);
+ sppProfileDescriptorList());
- classId.clear();
+ QBluetoothServiceInfo::Sequence classId;
//set SPP service class uuid
- classId << QVariant::fromValue(uuids.at(i));
+ classId << QVariant::fromValue(uuid);
classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId);
serviceInfo.setServiceName(QBluetoothServiceDiscoveryAgent::tr("Serial Port Profile"));
- serviceInfo.setServiceUuid(uuids.at(i));
- } else if (sppIndex == i && customUuids.isEmpty()) {
+ serviceInfo.setServiceUuid(uuid);
+ } else if (uuid == QBluetoothUuid{QBluetoothUuid::SerialPort}) {
//set rfcomm protocol
- QBluetoothServiceInfo::Sequence protocol;
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
- << QVariant::fromValue(0);
- protocolDescriptorList.append(QVariant::fromValue(protocol));
+ protocolDescriptorList.append(QVariant::fromValue(rfcommProtocolDescriptorList()));
- QBluetoothServiceInfo::Sequence profileSequence;
- QBluetoothServiceInfo::Sequence classId;
- classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
- classId << QVariant::fromValue(quint16(0x100));
- profileSequence.append(QVariant::fromValue(classId));
+ //set SPP profile descriptor list
serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList,
- profileSequence);
+ sppProfileDescriptorList());
//also we need to set the custom uuid to the SPP uuid
//otherwise QBluetoothSocket::connectToService() would fail due to a missing service uuid
- serviceInfo.setServiceUuid(uuids.at(i));
+ serviceInfo.setServiceUuid(uuid);
} else if (customUuids.contains(i)) {
//custom uuid but no serial port
- serviceInfo.setServiceUuid(uuids.at(i));
+ serviceInfo.setServiceUuid(uuid);
}
serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList);
@@ -419,18 +446,20 @@ void QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices(const QB
if (!customUuids.contains(i)) {
//if we don't have custom uuid use it as class id as well
QBluetoothServiceInfo::Sequence classId;
- classId << QVariant::fromValue(uuids.at(i));
+ classId << QVariant::fromValue(uuid);
serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId);
- QBluetoothUuid::ServiceClassUuid clsId
- = static_cast<QBluetoothUuid::ServiceClassUuid>(uuids.at(i).toUInt16());
+ auto clsId = QBluetoothUuid::ServiceClassUuid(uuid.toUInt16());
serviceInfo.setServiceName(QBluetoothUuid::serviceClassToString(clsId));
}
//Check if the service is in the uuidFilter
if (!uuidFilter.isEmpty()) {
bool match = uuidFilter.contains(serviceInfo.serviceUuid());
- for (const auto &uuid : qAsConst(uuidFilter))
+ match |= uuidFilter.contains(QBluetoothSocketPrivateAndroid::reverseUuid(serviceInfo.serviceUuid()));
+ for (const auto &uuid : qAsConst(uuidFilter)) {
match |= serviceInfo.serviceClassUuids().contains(uuid);
+ match |= serviceInfo.serviceClassUuids().contains(QBluetoothSocketPrivateAndroid::reverseUuid(uuid));
+ }
if (!match)
continue;