diff options
-rw-r--r-- | dist/changes-5.4.1 | 38 | ||||
-rw-r--r-- | examples/bluetooth/btchat/chatserver.cpp | 4 | ||||
-rw-r--r-- | examples/bluetooth/btchat/main.cpp | 2 | ||||
-rw-r--r-- | examples/bluetooth/btchat/remoteselector.cpp | 2 | ||||
-rw-r--r-- | src/bluetooth/android/localdevicebroadcastreceiver.cpp | 4 | ||||
-rw-r--r-- | src/bluetooth/bluez/bluez5_helper.cpp | 16 | ||||
-rw-r--r-- | src/bluetooth/bluez/bluez_data_p.h | 94 | ||||
-rw-r--r-- | src/bluetooth/bluez/hcimanager.cpp | 1 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothlocaldevice_android.cpp | 6 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothlocaldevice_bluez.cpp | 14 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothserver.cpp | 4 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothservicediscoveryagent.cpp | 5 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothservicediscoveryagent.h | 6 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp | 107 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothservicediscoveryagent_p.h | 6 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothsocket_android.cpp | 65 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_bluez.cpp | 2 |
17 files changed, 219 insertions, 157 deletions
diff --git a/dist/changes-5.4.1 b/dist/changes-5.4.1 new file mode 100644 index 00000000..5a4a5dba --- /dev/null +++ b/dist/changes-5.4.1 @@ -0,0 +1,38 @@ +Qt 5.4.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.4.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + http://doc.qt.io/qt-5.4 + +The Qt version 5.4 series is binary compatible with the 5.3.x series. +Applications compiled for 5.3 will continue to run with 5.4. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + http://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Library * +**************************************************************************** + +QtBluetooth +----------- + + - General: + * Extended documentation with regards to Bluetooth Low Energy. The + affected classes were QLowEnergyController and QLowEnergyService. + * LowEnergyScanner and chat examples improved. + + - QBluetoothServer: + * [QTBUG-43806] Fixed SDP registration of PublicBrowseGroup in BlueZ 5.x. + + - QLowEnergyController: + * Fixed blocking of ATT command processing due to a reconnect to the target + device. + diff --git a/examples/bluetooth/btchat/chatserver.cpp b/examples/bluetooth/btchat/chatserver.cpp index 6da4b471..6848e2d7 100644 --- a/examples/bluetooth/btchat/chatserver.cpp +++ b/examples/bluetooth/btchat/chatserver.cpp @@ -101,8 +101,10 @@ void ChatServer::startServer(const QBluetoothAddress& localAdapter) //! [Service UUID set] //! [Service Discoverability] + QBluetoothServiceInfo::Sequence publicBrowse; + publicBrowse << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup)); serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList, - QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup)); + publicBrowse); //! [Service Discoverability] //! [Protocol descriptor list] diff --git a/examples/bluetooth/btchat/main.cpp b/examples/bluetooth/btchat/main.cpp index ac23a11d..ed362d23 100644 --- a/examples/bluetooth/btchat/main.cpp +++ b/examples/bluetooth/btchat/main.cpp @@ -41,9 +41,11 @@ #include "chat.h" #include <QApplication> +//#include <QtCore/QLoggingCategory> int main(int argc, char *argv[]) { + //QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true")); QApplication app(argc, argv); Chat d; diff --git a/examples/bluetooth/btchat/remoteselector.cpp b/examples/bluetooth/btchat/remoteselector.cpp index 79dc0564..913988a2 100644 --- a/examples/bluetooth/btchat/remoteselector.cpp +++ b/examples/bluetooth/btchat/remoteselector.cpp @@ -136,6 +136,8 @@ void RemoteSelector::on_remoteDevices_itemActivated(QListWidgetItem *item) { qDebug() << "got click" << item->text(); m_service = m_discoveredServices.value(item); + if (m_discoveryAgent->isActive()) + m_discoveryAgent->stop(); accept(); } diff --git a/src/bluetooth/android/localdevicebroadcastreceiver.cpp b/src/bluetooth/android/localdevicebroadcastreceiver.cpp index c54c5e32..a3b92252 100644 --- a/src/bluetooth/android/localdevicebroadcastreceiver.cpp +++ b/src/bluetooth/android/localdevicebroadcastreceiver.cpp @@ -50,8 +50,8 @@ LocalDeviceBroadcastReceiver::LocalDeviceBroadcastReceiver(QObject *parent) : addAction(valueForStaticField(JavaNames::BluetoothAdapter, JavaNames::ActionScanModeChanged)); addAction(valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ActionAclConnected)); addAction(valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ActionAclDisconnected)); - if (QtAndroidPrivate::androidSdkVersion() >= 19) - addAction(valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ActionPairingRequest)); //API 19 + if (QtAndroidPrivate::androidSdkVersion() >= 15) + addAction(valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ActionPairingRequest)); //API 15 //cache integer values for host & bonding mode //don't use the java fields directly but refer to them by name diff --git a/src/bluetooth/bluez/bluez5_helper.cpp b/src/bluetooth/bluez/bluez5_helper.cpp index eebeae9d..0e3c0063 100644 --- a/src/bluetooth/bluez/bluez5_helper.cpp +++ b/src/bluetooth/bluez/bluez5_helper.cpp @@ -45,16 +45,16 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ) typedef enum Bluez5TestResultType { - Unknown, - Bluez4, - Bluez5 + BluezVersionUnknown, + BluezVersion4, + BluezVersion5 } Bluez5TestResult; -Q_GLOBAL_STATIC_WITH_ARGS(Bluez5TestResult, bluezVersion, (Bluez5TestResult::Unknown)); +Q_GLOBAL_STATIC_WITH_ARGS(Bluez5TestResult, bluezVersion, (BluezVersionUnknown)); bool isBluez5() { - if (*bluezVersion() == Bluez5TestResultType::Unknown) { + if (*bluezVersion() == BluezVersionUnknown) { OrgFreedesktopDBusObjectManagerInterface manager(QStringLiteral("org.bluez"), QStringLiteral("/"), QDBusConnection::systemBus()); @@ -65,15 +65,15 @@ bool isBluez5() QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects(); reply.waitForFinished(); if (reply.isError()) { - *bluezVersion() = Bluez5TestResultType::Bluez4; + *bluezVersion() = BluezVersion4; qCDebug(QT_BT_BLUEZ) << "Bluez 4 detected."; } else { - *bluezVersion() = Bluez5TestResultType::Bluez5; + *bluezVersion() = BluezVersion5; qCDebug(QT_BT_BLUEZ) << "Bluez 5 detected."; } } - return (*bluezVersion() == Bluez5TestResultType::Bluez5); + return (*bluezVersion() == BluezVersion5); } struct AdapterData diff --git a/src/bluetooth/bluez/bluez_data_p.h b/src/bluetooth/bluez/bluez_data_p.h index 7c799977..9d2d96b3 100644 --- a/src/bluetooth/bluez/bluez_data_p.h +++ b/src/bluetooth/bluez/bluez_data_p.h @@ -75,8 +75,8 @@ #define BT_SECURITY 4 struct bt_security { - uint8_t level; - uint8_t key_size; + quint8 level; + quint8 key_size; }; #define BT_SECURITY_SDP 0 #define BT_SECURITY_LOW 1 @@ -162,14 +162,14 @@ static inline void ntoh128(const quint128 *src, quint128 *dst) dst->data[15 - i] = src->data[i]; } -static inline uint16_t bt_get_le16(const void *ptr) +static inline quint16 bt_get_le16(const void *ptr) { - return bt_get_unaligned((const uint16_t *) ptr); + return bt_get_unaligned((const quint16 *) ptr); } #elif __BYTE_ORDER == __BIG_ENDIAN -static inline uint16_t bt_get_le16(const void *ptr) +static inline quint16 bt_get_le16(const void *ptr) { - return bswap_16(bt_get_unaligned((const uint16_t *) ptr)); + return bswap_16(bt_get_unaligned((const quint16 *) ptr)); } static inline void btoh128(const quint128 *src, quint128 *dst) @@ -213,79 +213,79 @@ struct sockaddr_hci { }; struct hci_dev_req { - uint16_t dev_id; - uint32_t dev_opt; + quint16 dev_id; + quint32 dev_opt; }; struct hci_dev_list_req { - uint16_t dev_num; + quint16 dev_num; struct hci_dev_req dev_req[0]; }; struct hci_dev_stats { - uint32_t err_rx; - uint32_t err_tx; - uint32_t cmd_tx; - uint32_t evt_rx; - uint32_t acl_tx; - uint32_t acl_rx; - uint32_t sco_tx; - uint32_t sco_rx; - uint32_t byte_rx; - uint32_t byte_tx; + quint32 err_rx; + quint32 err_tx; + quint32 cmd_tx; + quint32 evt_rx; + quint32 acl_tx; + quint32 acl_rx; + quint32 sco_tx; + quint32 sco_rx; + quint32 byte_rx; + quint32 byte_tx; }; struct hci_dev_info { - uint16_t dev_id; + quint16 dev_id; char name[8]; bdaddr_t bdaddr; - uint32_t flags; - uint8_t type; + quint32 flags; + quint8 type; - uint8_t features[8]; + quint8 features[8]; - uint32_t pkt_type; - uint32_t link_policy; - uint32_t link_mode; + quint32 pkt_type; + quint32 link_policy; + quint32 link_mode; - uint16_t acl_mtu; - uint16_t acl_pkts; - uint16_t sco_mtu; - uint16_t sco_pkts; + quint16 acl_mtu; + quint16 acl_pkts; + quint16 sco_mtu; + quint16 sco_pkts; struct hci_dev_stats stat; }; struct hci_conn_info { - uint16_t handle; + quint16 handle; bdaddr_t bdaddr; - uint8_t type; - uint8_t out; - uint16_t state; - uint32_t link_mode; + quint8 type; + quint8 out; + quint16 state; + quint32 link_mode; }; struct hci_conn_list_req { - uint16_t dev_id; - uint16_t conn_num; + quint16 dev_id; + quint16 conn_num; struct hci_conn_info conn_info[0]; }; struct hci_filter { - uint32_t type_mask; - uint32_t event_mask[2]; - uint16_t opcode; + quint32 type_mask; + quint32 event_mask[2]; + quint16 opcode; }; static inline void hci_set_bit(int nr, void *addr) { - *((uint32_t *) addr + (nr >> 5)) |= (1 << (nr & 31)); + *((quint32 *) addr + (nr >> 5)) |= (1 << (nr & 31)); } static inline void hci_clear_bit(int nr, void *addr) { - *((uint32_t *) addr + (nr >> 5)) &= ~(1 << (nr & 31)); + *((quint32 *) addr + (nr >> 5)) &= ~(1 << (nr & 31)); } static inline void hci_filter_clear(struct hci_filter *f) { @@ -317,16 +317,16 @@ static inline void hci_filter_all_events(struct hci_filter *f) } typedef struct { - uint8_t evt; - uint8_t plen; + quint8 evt; + quint8 plen; } __attribute__ ((packed)) hci_event_hdr; #define HCI_EVENT_HDR_SIZE 2 #define EVT_ENCRYPT_CHANGE 0x08 typedef struct { - uint8_t status; - uint16_t handle; - uint8_t encrypt; + quint8 status; + quint16 handle; + quint8 encrypt; } __attribute__ ((packed)) evt_encrypt_change; #define EVT_ENCRYPT_CHANGE_SIZE 4 diff --git a/src/bluetooth/bluez/hcimanager.cpp b/src/bluetooth/bluez/hcimanager.cpp index 17d54a4b..32450588 100644 --- a/src/bluetooth/bluez/hcimanager.cpp +++ b/src/bluetooth/bluez/hcimanager.cpp @@ -38,6 +38,7 @@ #include <QtCore/QLoggingCategory> +#include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> diff --git a/src/bluetooth/qbluetoothlocaldevice_android.cpp b/src/bluetooth/qbluetoothlocaldevice_android.cpp index 4c1b1d4e..11515743 100644 --- a/src/bluetooth/qbluetoothlocaldevice_android.cpp +++ b/src/bluetooth/qbluetoothlocaldevice_android.cpp @@ -376,9 +376,9 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai return; } - // BluetoothDevice::createBond() requires Android API 19 - if (QtAndroidPrivate::androidSdkVersion() < 19 || !d_ptr->adapter()) { - qCWarning(QT_BT_ANDROID) << "Unable to pair: requires Android API 19+"; + // BluetoothDevice::createBond() requires Android API 15 + if (QtAndroidPrivate::androidSdkVersion() < 15 || !d_ptr->adapter()) { + qCWarning(QT_BT_ANDROID) << "Unable to pair: requires Android API 15+"; QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, Q_ARG(QBluetoothLocalDevice::Error, QBluetoothLocalDevice::PairingError)); diff --git a/src/bluetooth/qbluetoothlocaldevice_bluez.cpp b/src/bluetooth/qbluetoothlocaldevice_bluez.cpp index c7ee556d..0df7cc5d 100644 --- a/src/bluetooth/qbluetoothlocaldevice_bluez.cpp +++ b/src/bluetooth/qbluetoothlocaldevice_bluez.cpp @@ -345,6 +345,7 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, Q_ARG(QBluetoothLocalDevice::Error, QBluetoothLocalDevice::PairingError)); + delete device; return; } delete device; @@ -368,6 +369,7 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, Q_ARG(QBluetoothLocalDevice::Error, QBluetoothLocalDevice::PairingError)); + delete device; return; } delete device; @@ -579,15 +581,21 @@ QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus( QDBusPendingReply<QVariantMap> deviceReply = device->GetProperties(); deviceReply.waitForFinished(); - if (deviceReply.isError()) + if (deviceReply.isError()) { + delete device; return Unpaired; + } QVariantMap map = deviceReply.value(); - if (map.value(QStringLiteral("Trusted")).toBool() && map.value(QStringLiteral("Paired")).toBool()) + if (map.value(QStringLiteral("Trusted")).toBool() && map.value(QStringLiteral("Paired")).toBool()) { + delete device; return AuthorizedPaired; - else if (map.value(QStringLiteral("Paired")).toBool()) + } else if (map.value(QStringLiteral("Paired")).toBool()) { + delete device; return Paired; + } + delete device; } else if (d_ptr->adapterBluez5) { QDBusPendingReply<ManagedObjectList> reply = d_ptr->managerBluez5->GetManagedObjects(); diff --git a/src/bluetooth/qbluetoothserver.cpp b/src/bluetooth/qbluetoothserver.cpp index 3001a00b..1c4676e0 100644 --- a/src/bluetooth/qbluetoothserver.cpp +++ b/src/bluetooth/qbluetoothserver.cpp @@ -204,8 +204,10 @@ QBluetoothServiceInfo QBluetoothServer::listen(const QBluetoothUuid &uuid, const //! [listen] QBluetoothServiceInfo serviceInfo; serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceName, serviceName); + QBluetoothServiceInfo::Sequence browseSequence; + browseSequence << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup)); serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList, - QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup)); + browseSequence); QBluetoothServiceInfo::Sequence classId; classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort)); diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.cpp b/src/bluetooth/qbluetoothservicediscoveryagent.cpp index ef28ef82..7274780a 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent.cpp @@ -183,6 +183,11 @@ QBluetoothServiceDiscoveryAgent::QBluetoothServiceDiscoveryAgent(const QBluetoot QBluetoothServiceDiscoveryAgent::~QBluetoothServiceDiscoveryAgent() { + if (isActive()) { + disconnect(); //don't emit any signals due to stop() + stop(); + } + delete d_ptr; } diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.h b/src/bluetooth/qbluetoothservicediscoveryagent.h index 787d58e3..d9f005cd 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent.h +++ b/src/bluetooth/qbluetoothservicediscoveryagent.h @@ -42,6 +42,10 @@ #include <QtBluetooth/QBluetoothUuid> #include <QtBluetooth/QBluetoothDeviceDiscoveryAgent> +#ifdef QT_BLUEZ_BLUETOOTH +#include <QtCore/qprocess.h> +#endif + QT_BEGIN_NAMESPACE class QBluetoothAddress; @@ -108,7 +112,7 @@ private: #ifdef QT_BLUEZ_BLUETOOTH Q_PRIVATE_SLOT(d_func(), void _q_discoveredServices(QDBusPendingCallWatcher*)) Q_PRIVATE_SLOT(d_func(), void _q_createdDevice(QDBusPendingCallWatcher*)) - Q_PRIVATE_SLOT(d_func(), void _q_finishSdpScan(QBluetoothServiceDiscoveryAgent::Error, const QString &, const QStringList &)) + Q_PRIVATE_SLOT(d_func(), void _q_sdpScannerDone(int,QProcess::ExitStatus)) #endif #ifdef QT_ANDROID_BLUETOOTH Q_PRIVATE_SLOT(d_func(), void _q_processFetchedUuids(const QBluetoothAddress &address, diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp index 6958e1b2..90baf1f8 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp @@ -65,7 +65,7 @@ static inline void convertAddress(quint64 from, quint8 (&to)[6]) QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(const QBluetoothAddress &deviceAdapter) : error(QBluetoothServiceDiscoveryAgent::NoError), m_deviceAdapterAddress(deviceAdapter), state(Inactive), deviceDiscoveryAgent(0), mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery), singleDevice(false), - manager(0), managerBluez5(0), adapter(0), device(0) + manager(0), managerBluez5(0), adapter(0), device(0), sdpScannerProcess(0) { if (isBluez5()) { managerBluez5 = new OrgFreedesktopDBusObjectManagerInterface( @@ -136,6 +136,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr } +// Bluez 5 void QBluetoothServiceDiscoveryAgentPrivate::startBluez5(const QBluetoothAddress &address) { Q_Q(QBluetoothServiceDiscoveryAgent); @@ -185,81 +186,64 @@ void QBluetoothServiceDiscoveryAgentPrivate::startBluez5(const QBluetoothAddress if (DiscoveryMode() == QBluetoothServiceDiscoveryAgent::MinimalDiscovery) { performMinimalServiceDiscovery(address); } else { - // we need to run the discovery in a different thread - // as it involves blocking calls - QtConcurrent::run(this, &QBluetoothServiceDiscoveryAgentPrivate::runSdpScan, - address, QBluetoothAddress(adapter.address())); + runExternalSdpScan(address, QBluetoothAddress(adapter.address())); } } -/* - * This function runs in a different thread. We need to be very careful what we - * access from here. That's why invokeMethod is used below. - * +/* Bluez 5 * src/tools/sdpscanner performs an SDP scan. This is * done out-of-process to avoid license issues. At this stage Bluez uses GPLv2. */ -void QBluetoothServiceDiscoveryAgentPrivate::runSdpScan( +void QBluetoothServiceDiscoveryAgentPrivate::runExternalSdpScan( const QBluetoothAddress &remoteAddress, const QBluetoothAddress localAddress) { Q_Q(QBluetoothServiceDiscoveryAgent); - const QString binPath = QLibraryInfo::location(QLibraryInfo::BinariesPath); - - QFileInfo fileInfo(binPath, QStringLiteral("sdpscanner")); - if (!fileInfo.exists() || !fileInfo.isExecutable()) { - QMetaObject::invokeMethod(q, "_q_finishSdpScan", Qt::QueuedConnection, - Q_ARG(QBluetoothServiceDiscoveryAgent::Error, - QBluetoothServiceDiscoveryAgent::InputOutputError), - Q_ARG(QString, - QBluetoothServiceDiscoveryAgent::tr("Unable to find sdpscanner")), - Q_ARG(QStringList, QStringList())); - qCWarning(QT_BT_BLUEZ) << "Cannot find sdpscanner:" - << fileInfo.canonicalFilePath(); - return; + if (!sdpScannerProcess) { + const QString binPath = QLibraryInfo::location(QLibraryInfo::BinariesPath); + QFileInfo fileInfo(binPath, QStringLiteral("sdpscanner")); + if (!fileInfo.exists() || !fileInfo.isExecutable()) { + _q_finishSdpScan(QBluetoothServiceDiscoveryAgent::InputOutputError, + QBluetoothServiceDiscoveryAgent::tr("Unable to find sdpscanner"), + QStringList()); + qCWarning(QT_BT_BLUEZ) << "Cannot find sdpscanner:" + << fileInfo.canonicalFilePath(); + return; + } + + sdpScannerProcess = new QProcess(q); + sdpScannerProcess->setReadChannel(QProcess::StandardOutput); + sdpScannerProcess->setProgram(fileInfo.canonicalFilePath()); + q->connect(sdpScannerProcess, SIGNAL(finished(int,QProcess::ExitStatus)), + q, SLOT(_q_sdpScannerDone(int,QProcess::ExitStatus))); + } QStringList arguments; arguments << remoteAddress.toString() << localAddress.toString(); - QByteArray output; - - QProcess process; - process.setProcessChannelMode(QProcess::ForwardedErrorChannel); - process.setReadChannel(QProcess::StandardOutput); - process.start(fileInfo.canonicalFilePath(), arguments); - - if (process.waitForStarted(-1)) { - while (process.waitForReadyRead(-1)) - output += process.readAllStandardOutput(); - } - - process.waitForFinished(); + sdpScannerProcess->setArguments(arguments); + sdpScannerProcess->start(); +} - if (process.exitStatus() != QProcess::NormalExit - || process.exitCode() != 0) { - qCWarning(QT_BT_BLUEZ) << "SDP scan failure" - << process.exitStatus() << process.exitCode() - << remoteAddress; +// Bluez 5 +void QBluetoothServiceDiscoveryAgentPrivate::_q_sdpScannerDone(int exitCode, QProcess::ExitStatus status) +{ + if (status != QProcess::NormalExit || exitCode != 0) { + qCWarning(QT_BT_BLUEZ) << "SDP scan failure" << status << exitCode; if (singleDevice) { - QMetaObject::invokeMethod(q, "_q_finishSdpScan", Qt::QueuedConnection, - Q_ARG(QBluetoothServiceDiscoveryAgent::Error, - QBluetoothServiceDiscoveryAgent::InputOutputError), - Q_ARG(QString, - QBluetoothServiceDiscoveryAgent::tr("Unable to perform SDP scan")), - Q_ARG(QStringList, QStringList())); + _q_finishSdpScan(QBluetoothServiceDiscoveryAgent::InputOutputError, + QBluetoothServiceDiscoveryAgent::tr("Unable to perform SDP scan"), + QStringList()); } else { // go to next device - QMetaObject::invokeMethod(q, "_q_finishSdpScan", Qt::QueuedConnection, - Q_ARG(QBluetoothServiceDiscoveryAgent::Error, - QBluetoothServiceDiscoveryAgent::NoError), - Q_ARG(QString, QString()), - Q_ARG(QStringList, QStringList())); + _q_finishSdpScan(QBluetoothServiceDiscoveryAgent::NoError, QString(), QStringList()); } return; } QStringList xmlRecords; + const QByteArray output = sdpScannerProcess->readAllStandardOutput(); const QString decodedData = QString::fromUtf8(QByteArray::fromBase64(output)); // split the various xml docs up @@ -276,13 +260,10 @@ void QBluetoothServiceDiscoveryAgentPrivate::runSdpScan( } while ( start != -1); } - QMetaObject::invokeMethod(q, "_q_finishSdpScan", Qt::QueuedConnection, - Q_ARG(QBluetoothServiceDiscoveryAgent::Error, - QBluetoothServiceDiscoveryAgent::NoError), - Q_ARG(QString, QString()), - Q_ARG(QStringList, xmlRecords)); + _q_finishSdpScan(QBluetoothServiceDiscoveryAgent::NoError, QString(), xmlRecords); } +// Bluez 5 void QBluetoothServiceDiscoveryAgentPrivate::_q_finishSdpScan(QBluetoothServiceDiscoveryAgent::Error errorCode, const QString &errorDescription, const QStringList &xmlRecords) @@ -352,8 +333,19 @@ void QBluetoothServiceDiscoveryAgentPrivate::stop() Q_ASSERT(!device); } + discoveredDevices.clear(); setDiscoveryState(Inactive); + + // must happen after discoveredDevices.clear() above to avoid retrigger of next scan + // while waitForFinished() is waiting + if (sdpScannerProcess) { // Bluez 5 + if (sdpScannerProcess->state() != QProcess::NotRunning) { + sdpScannerProcess->kill(); + sdpScannerProcess->waitForFinished(); + } + } + Q_Q(QBluetoothServiceDiscoveryAgent); emit q->canceled(); } @@ -591,6 +583,7 @@ QBluetoothServiceInfo QBluetoothServiceDiscoveryAgentPrivate::parseServiceXml( return serviceInfo; } +// Bluez 5 void QBluetoothServiceDiscoveryAgentPrivate::performMinimalServiceDiscovery(const QBluetoothAddress &deviceAddress) { if (foundHostAdapterPath.isEmpty()) { diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_p.h b/src/bluetooth/qbluetoothservicediscoveryagent_p.h index ea985627..3b9c0a42 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_p.h +++ b/src/bluetooth/qbluetoothservicediscoveryagent_p.h @@ -58,6 +58,7 @@ class OrgBluezManagerInterface; class OrgBluezAdapterInterface; class OrgBluezDeviceInterface; class OrgFreedesktopDBusObjectManagerInterface; +#include <QtCore/qprocess.h> QT_BEGIN_NAMESPACE class QDBusPendingCallWatcher; @@ -127,6 +128,7 @@ public: void _q_discoverGattCharacteristics(QDBusPendingCallWatcher *watcher); void _q_discoveredGattCharacteristic(QDBusPendingCallWatcher *watcher); */ + void _q_sdpScannerDone(int exitCode, QProcess::ExitStatus status); void _q_finishSdpScan(QBluetoothServiceDiscoveryAgent::Error errorCode, const QString &errorDescription, const QStringList &xmlRecords); @@ -147,8 +149,9 @@ private: #ifdef QT_BLUEZ_BLUETOOTH void startBluez5(const QBluetoothAddress &address); - void runSdpScan(const QBluetoothAddress &remoteAddress, + void runExternalSdpScan(const QBluetoothAddress &remoteAddress, const QBluetoothAddress localAddress); + void sdpScannerDone(int exitCode, QProcess::ExitStatus exitStatus); QVariant readAttributeValue(QXmlStreamReader &xml); QBluetoothServiceInfo parseServiceXml(const QString& xml); void performMinimalServiceDiscovery(const QBluetoothAddress &deviceAddress); @@ -195,6 +198,7 @@ private: OrgFreedesktopDBusObjectManagerInterface *managerBluez5; OrgBluezAdapterInterface *adapter; OrgBluezDeviceInterface *device; + QProcess *sdpScannerProcess; #endif #ifdef QT_ANDROID_BLUETOOTH diff --git a/src/bluetooth/qbluetoothsocket_android.cpp b/src/bluetooth/qbluetoothsocket_android.cpp index 02440abc..c3380836 100644 --- a/src/bluetooth/qbluetoothsocket_android.cpp +++ b/src/bluetooth/qbluetoothsocket_android.cpp @@ -37,6 +37,7 @@ #include "qbluetoothaddress.h" #include <QtCore/QLoggingCategory> #include <QtCore/QTime> +#include <QtCore/private/qjni_p.h> #include <QtConcurrent/QtConcurrentRun> #include <QtAndroidExtras/QAndroidJniEnvironment> @@ -90,32 +91,37 @@ bool QBluetoothSocketPrivate::fallBackConnect(QAndroidJniObject uuid, int channe qCWarning(QT_BT_ANDROID) << "Falling back to workaround."; QAndroidJniEnvironment env; - jclass remoteDeviceClazz = env->GetObjectClass(remoteDevice.object()); - jmethodID getClassMethod = env->GetMethodID(remoteDeviceClazz, "getClass", "()Ljava/lang/Class;"); - if (!getClassMethod) { - qCWarning(QT_BT_ANDROID) << "BluetoothDevice.getClass method could not be found."; - return false; - } - - QAndroidJniObject remoteDeviceClass = QAndroidJniObject(env->CallObjectMethod(remoteDevice.object(), getClassMethod)); + QAndroidJniObject remoteDeviceClass = remoteDevice.callObjectMethod("getClass", "()Ljava/lang/Class;"); if (!remoteDeviceClass.isValid()) { qCWarning(QT_BT_ANDROID) << "Could not invoke BluetoothDevice.getClass."; return false; } - jclass classClass = env->FindClass("java/lang/Class"); - jclass integerClass = env->FindClass("java/lang/Integer"); - jfieldID integerType = env->GetStaticFieldID(integerClass, "TYPE", "Ljava/lang/Class;"); - jobject integerObject = env->GetStaticObjectField(integerClass, integerType); - if (!integerObject) { + QAndroidJniObject integerObject = QAndroidJniObject::getStaticObjectField<jobject>( + "java/lang/Integer", "TYPE", "Ljava/lang/Class;"); + if (!integerObject.isValid()) { qCWarning(QT_BT_ANDROID) << "Could not get Integer.TYPE"; + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + return false; } - jobjectArray paramTypes = env->NewObjectArray(1, classClass, integerObject); - if (!paramTypes) { + jclass classClass = QJNIEnvironmentPrivate::findClass("java/lang/Class"); + jobjectArray rawArray = env->NewObjectArray(1, classClass, + integerObject.object<jobject>()); + QAndroidJniObject paramTypes(rawArray); + env->DeleteLocalRef(rawArray); + if (!paramTypes.isValid()) { qCWarning(QT_BT_ANDROID) << "Could not create new Class[]{Integer.TYPE}"; + + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } return false; } @@ -143,7 +149,7 @@ bool QBluetoothSocketPrivate::fallBackConnect(QAndroidJniObject uuid, int channe "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", QAndroidJniObject::fromString(QLatin1String("createRfcommSocket")).object<jstring>(), - paramTypes); + paramTypes.object<jobjectArray>()); if (!method.isValid() || env->ExceptionCheck()) { qCWarning(QT_BT_ANDROID) << "Could not invoke getMethod"; if (env->ExceptionCheck()) { @@ -153,29 +159,23 @@ bool QBluetoothSocketPrivate::fallBackConnect(QAndroidJniObject uuid, int channe return false; } - jclass methodClass = env->GetObjectClass(method.object()); - jmethodID invokeMethodId = env->GetMethodID( - methodClass, "invoke", - "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); - if (!invokeMethodId) { - qCWarning(QT_BT_ANDROID) << "Could not invoke method."; - return false; - } + jclass objectClass = QJNIEnvironmentPrivate::findClass("java/lang/Object"); + QAndroidJniObject channelObject = QAndroidJniObject::callStaticObjectMethod( + "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", channel); + rawArray = env->NewObjectArray(1, objectClass, channelObject.object<jobject>()); - jmethodID valueOfMethodId = env->GetStaticMethodID(integerClass, "valueOf", "(I)Ljava/lang/Integer;"); - jclass objectClass = env->FindClass("java/lang/Object"); - jobjectArray invokeParams = env->NewObjectArray(1, objectClass, env->CallStaticObjectMethod(integerClass, valueOfMethodId, channel)); - - - jobject invokeResult = env->CallObjectMethod(method.object(), invokeMethodId, - remoteDevice.object(), invokeParams); - if (!invokeResult) + QAndroidJniObject invokeResult = method.callObjectMethod("invoke", + "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", + remoteDevice.object<jobject>(), rawArray); + env->DeleteLocalRef(rawArray); + if (!invokeResult.isValid()) { qCWarning(QT_BT_ANDROID) << "Invoke Resulted with error."; if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); } + return false; } @@ -186,7 +186,6 @@ bool QBluetoothSocketPrivate::fallBackConnect(QAndroidJniObject uuid, int channe env->ExceptionClear(); qCWarning(QT_BT_ANDROID) << "Socket connect via workaround failed."; - return false; } diff --git a/src/bluetooth/qlowenergycontroller_bluez.cpp b/src/bluetooth/qlowenergycontroller_bluez.cpp index 63de6edb..ae354bc7 100644 --- a/src/bluetooth/qlowenergycontroller_bluez.cpp +++ b/src/bluetooth/qlowenergycontroller_bluez.cpp @@ -41,6 +41,8 @@ #include <QtBluetooth/QBluetoothSocket> #include <QtBluetooth/QLowEnergyService> +#include <errno.h> + #define ATTRIBUTE_CHANNEL_ID 4 #define ATT_DEFAULT_LE_MTU 23 |