diff options
-rw-r--r-- | src/bluetooth/qbluetoothservicediscoveryagent_android.cpp | 85 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothsocket.cpp | 7 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothsocket_android.cpp | 28 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothsocket_winrt.cpp | 2 |
4 files changed, 78 insertions, 44 deletions
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp index e607a27e..3ab0d580 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp @@ -336,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; @@ -384,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); @@ -440,10 +446,9 @@ 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)); } diff --git a/src/bluetooth/qbluetoothsocket.cpp b/src/bluetooth/qbluetoothsocket.cpp index e6e1d955..a18b8ed4 100644 --- a/src/bluetooth/qbluetoothsocket.cpp +++ b/src/bluetooth/qbluetoothsocket.cpp @@ -360,8 +360,8 @@ qint64 QBluetoothSocket::bytesToWrite() const /*! Attempts to connect to the service described by \a service. - The socket is opened in the given \a openMode. The \l socketType() may change - depending on the protocol required by \a service. + The socket is opened in the given \a openMode. The \l socketType() is ignored + if \a service specifies a differing \l QBluetoothServiceInfo::socketProtocol(). The socket first enters ConnectingState and attempts to connect to the device providing \a service. If a connection is established, QBluetoothSocket enters ConnectedState and @@ -372,6 +372,9 @@ qint64 QBluetoothSocket::bytesToWrite() const Note that most platforms require a pairing prior to connecting to the remote device. Otherwise the connection process may fail. + On Android, only RFCOMM connections are possible. This function ignores any socket protocol indicator + and assumes RFCOMM. + \sa state(), disconnectFromService() */ void QBluetoothSocket::connectToService(const QBluetoothServiceInfo &service, OpenMode openMode) diff --git a/src/bluetooth/qbluetoothsocket_android.cpp b/src/bluetooth/qbluetoothsocket_android.cpp index 46bd4a23..85da325b 100644 --- a/src/bluetooth/qbluetoothsocket_android.cpp +++ b/src/bluetooth/qbluetoothsocket_android.cpp @@ -494,7 +494,33 @@ void QBluetoothSocketPrivateAndroid::connectToService( return; } - if (!ensureNativeSocket(service.socketProtocol())) { + // Workaround for QTBUG-75035 + /* Not all Android devices publish or discover the SPP uuid for serial services. + * Also, Android does not permit the detection of the protocol used by a serial + * Bluetooth connection. + * + * Therefore, QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices() + * may have to guess what protocol a potential custom uuid uses. The guessing works + * reasonably well as long as the SDP discovery finds the SPP uuid. Otherwise + * the SPP and rfcomm protocol info is missing in \a service. + * + * Android only supports RFCOMM (no L2CP). We assume (in favor of user experience) + * that a non-RFCOMM protocol implies a missing SPP uuid during discovery but the user + * still wanting to connect with the given \a service instance. + */ + + auto protocol = service.socketProtocol(); + switch (protocol) { + case QBluetoothServiceInfo::L2capProtocol: + case QBluetoothServiceInfo::UnknownProtocol: + qCWarning(QT_BT_ANDROID) << "Changing socket protocol to RFCOMM"; + protocol = QBluetoothServiceInfo::RfcommProtocol; + break; + case QBluetoothServiceInfo::RfcommProtocol: + break; + } + + if (!ensureNativeSocket(protocol)) { errorString = QBluetoothSocket::tr("Socket type not supported"); q->setSocketError(QBluetoothSocket::UnsupportedProtocolError); return; diff --git a/src/bluetooth/qbluetoothsocket_winrt.cpp b/src/bluetooth/qbluetoothsocket_winrt.cpp index 79dccdd6..a4af8f72 100644 --- a/src/bluetooth/qbluetoothsocket_winrt.cpp +++ b/src/bluetooth/qbluetoothsocket_winrt.cpp @@ -765,7 +765,7 @@ HRESULT QBluetoothSocketPrivateWinRT::handleConnectOpFinished(ABI::Windows::Foun return S_OK; } - HRESULT hr = action->GetResults(); + DWORD hr = action->GetResults(); switch (hr) { case 0x8007274c: // A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. errorString = QBluetoothSocket::tr("Connection timed out"); |