diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java | 4 | ||||
-rw-r--r-- | src/bluetooth/android/androidbroadcastreceiver_p.h | 4 | ||||
-rw-r--r-- | src/bluetooth/android/devicediscoverybroadcastreceiver.cpp | 85 | ||||
-rw-r--r-- | src/bluetooth/android/devicediscoverybroadcastreceiver_p.h | 5 | ||||
-rw-r--r-- | src/bluetooth/android/jni_android.cpp | 8 | ||||
-rw-r--r-- | src/bluetooth/android/localdevicebroadcastreceiver_p.h | 2 | ||||
-rw-r--r-- | src/bluetooth/android/servicediscoverybroadcastreceiver_p.h | 2 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp | 8 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller.cpp | 22 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller.h | 1 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_osx.mm | 7 | ||||
-rw-r--r-- | src/nfc/nfc.pro | 1 | ||||
-rw-r--r-- | src/nfc/qllcpserver.cpp | 2 |
13 files changed, 135 insertions, 16 deletions
diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java index faf45621..481f2917 100644 --- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java +++ b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java @@ -115,11 +115,11 @@ public class QtBluetoothLE { if (qtObject == 0) return; - leScanResult(qtObject, device, rssi); + leScanResult(qtObject, device, rssi, scanRecord); } }; - public native void leScanResult(long qtObject, BluetoothDevice device, int rssi); + public native void leScanResult(long qtObject, BluetoothDevice device, int rssi, byte[] scanRecord); /*************************************************************/ /* Service Discovery */ diff --git a/src/bluetooth/android/androidbroadcastreceiver_p.h b/src/bluetooth/android/androidbroadcastreceiver_p.h index 01d57992..ed30acad 100644 --- a/src/bluetooth/android/androidbroadcastreceiver_p.h +++ b/src/bluetooth/android/androidbroadcastreceiver_p.h @@ -75,8 +75,8 @@ public: protected: friend void QtBroadcastReceiver_jniOnReceive(JNIEnv *, jobject, jlong, jobject, jobject); virtual void onReceive(JNIEnv *env, jobject context, jobject intent) = 0; - friend void QtBluetoothLE_leScanResult(JNIEnv *, jobject, jlong, jobject, jint); - virtual void onReceiveLeScan(JNIEnv *env, jobject jBluetoothDevice, jint rssi) = 0; + friend void QtBluetoothLE_leScanResult(JNIEnv *, jobject, jlong, jobject, jint, jbyteArray); + virtual void onReceiveLeScan(JNIEnv *env, jobject jBluetoothDevice, jint rssi, jbyteArray scanRecord) = 0; QAndroidJniObject contextObject; diff --git a/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp b/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp index a246889f..c807df7f 100644 --- a/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp +++ b/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp @@ -39,13 +39,16 @@ ****************************************************************************/ #include "android/devicediscoverybroadcastreceiver_p.h" +#include <QtCore/QtEndian> #include <QtCore/QLoggingCategory> #include <QtBluetooth/QBluetoothAddress> #include <QtBluetooth/QBluetoothDeviceInfo> +#include <QtBluetooth/QBluetoothUuid> #include "android/jni_android_p.h" #include <QtCore/private/qjnihelpers_p.h> #include <QtCore/QHash> #include <QtCore/qbitarray.h> +#include <algorithm> QT_BEGIN_NAMESPACE @@ -234,6 +237,27 @@ static const MinorClassJavaToQtMapping minorMappings[] = { { Q_NULLPTR, 0 }, // index 64 & separator }; +/*! Advertising Data Type (AD type) for LE scan records, as defined in Bluetooth CSS v6. */ +enum ADType { + ADType16BitUuidIncomplete = 0x02, + ADType16BitUuidComplete = 0x03, + ADType32BitUuidIncomplete = 0x04, + ADType32BitUuidComplete = 0x05, + ADType128BitUuidIncomplete = 0x06, + ADType128BitUuidComplete = 0x07, + // .. more will be added when required +}; + +// Endianness conversion for quint128 doesn't (yet) exist in qtendian.h +template <> +inline quint128 qbswap<quint128>(const quint128 src) +{ + quint128 dst; + for (int i = 0; i < 16; i++) + dst.data[i] = src.data[15 - i]; + return dst; +} + QBluetoothDeviceInfo::CoreConfigurations qtBtTypeForJavaBtType(jint javaType) { const JCachedBtTypes::iterator it = cachedBtTypes()->find(javaType); @@ -425,19 +449,18 @@ void DeviceDiscoveryBroadcastReceiver::onReceive(JNIEnv *env, jobject context, j // Runs in Java thread void DeviceDiscoveryBroadcastReceiver::onReceiveLeScan( - JNIEnv *env, jobject jBluetoothDevice, jint rssi) + JNIEnv *env, jobject jBluetoothDevice, jint rssi, jbyteArray scanRecord) { - qCDebug(QT_BT_ANDROID) << "DeviceDiscoveryBroadcastReceiver::onReceiveLeScan()"; const QAndroidJniObject bluetoothDevice(jBluetoothDevice); if (!bluetoothDevice.isValid()) return; - const QBluetoothDeviceInfo info = retrieveDeviceInfo(env, bluetoothDevice, rssi); + const QBluetoothDeviceInfo info = retrieveDeviceInfo(env, bluetoothDevice, rssi, scanRecord); if (info.isValid()) emit deviceDiscovered(info, true); } -QBluetoothDeviceInfo DeviceDiscoveryBroadcastReceiver::retrieveDeviceInfo(JNIEnv *env, const QAndroidJniObject &bluetoothDevice, int rssi) +QBluetoothDeviceInfo DeviceDiscoveryBroadcastReceiver::retrieveDeviceInfo(JNIEnv *env, const QAndroidJniObject &bluetoothDevice, int rssi, jbyteArray scanRecord) { const QString deviceName = bluetoothDevice.callObjectMethod<jstring>("getName").toString(); const QBluetoothAddress deviceAddress(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString()); @@ -485,6 +508,60 @@ QBluetoothDeviceInfo DeviceDiscoveryBroadcastReceiver::retrieveDeviceInfo(JNIEnv QBluetoothDeviceInfo info(deviceAddress, deviceName, classType); info.setRssi(rssi); + if (scanRecord != nullptr) { + // Parse scan record + jboolean isCopy; + const char *scanRecordBuffer = reinterpret_cast<const char *>(env->GetByteArrayElements(scanRecord, &isCopy)); + const int scanRecordLength = env->GetArrayLength(scanRecord); + + QList<QBluetoothUuid> serviceUuids; + int i = 0; + + // Spec 4.2, Vol 3, Part C, Chapter 11 + while (i < scanRecordLength) { + // sizeof(EIR Data) = sizeof(Length) + sizeof(EIR data Type) + sizeof(EIR Data) + // Length = sizeof(EIR data Type) + sizeof(EIR Data) + + const int nBytes = scanRecordBuffer[i]; + if (nBytes == 0) + break; + + if ((i + nBytes) >= scanRecordLength) + break; + + const int adType = scanRecordBuffer[i+1]; + const char *dataPtr = &scanRecordBuffer[i+2]; + QBluetoothUuid foundService; + + switch (adType) { + case ADType16BitUuidIncomplete: + case ADType16BitUuidComplete: + foundService = QBluetoothUuid(qFromLittleEndian<quint16>(dataPtr)); + break; + case ADType32BitUuidIncomplete: + case ADType32BitUuidComplete: + foundService = QBluetoothUuid(qFromLittleEndian<quint32>(dataPtr)); + break; + case ADType128BitUuidIncomplete: + case ADType128BitUuidComplete: + foundService = + QBluetoothUuid(qToBigEndian<quint128>(qFromLittleEndian<quint128>(dataPtr))); + break; + default: + // no other types supported yet and therefore skipped + // https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile + break; + } + + i += nBytes + 1; + + if (!foundService.isNull() && !serviceUuids.contains(foundService)) + serviceUuids.append(foundService); + } + + info.setServiceUuids(serviceUuids, QBluetoothDeviceInfo::DataIncomplete); + } + if (QtAndroidPrivate::androidSdkVersion() >= 18) { jint javaBtType = bluetoothDevice.callMethod<jint>("getType"); diff --git a/src/bluetooth/android/devicediscoverybroadcastreceiver_p.h b/src/bluetooth/android/devicediscoverybroadcastreceiver_p.h index 835a7654..526c57e2 100644 --- a/src/bluetooth/android/devicediscoverybroadcastreceiver_p.h +++ b/src/bluetooth/android/devicediscoverybroadcastreceiver_p.h @@ -65,7 +65,8 @@ class DeviceDiscoveryBroadcastReceiver : public AndroidBroadcastReceiver public: DeviceDiscoveryBroadcastReceiver(QObject* parent = 0); virtual void onReceive(JNIEnv *env, jobject context, jobject intent); - virtual void onReceiveLeScan(JNIEnv *env, jobject jBluetoothDevice, jint rssi); + virtual void onReceiveLeScan(JNIEnv *env, jobject jBluetoothDevice, jint rssi, + jbyteArray scanRecord); signals: void deviceDiscovered(const QBluetoothDeviceInfo &info, bool isLeScanResult); @@ -73,7 +74,7 @@ signals: private: QBluetoothDeviceInfo retrieveDeviceInfo(JNIEnv *env, const QAndroidJniObject& bluetoothDevice, - int rssi); + int rssi, jbyteArray scanRecord = nullptr); }; QT_END_NAMESPACE diff --git a/src/bluetooth/android/jni_android.cpp b/src/bluetooth/android/jni_android.cpp index 95011c6c..ae07608a 100644 --- a/src/bluetooth/android/jni_android.cpp +++ b/src/bluetooth/android/jni_android.cpp @@ -190,10 +190,12 @@ static void QtBluetoothInputStreamThread_readyData(JNIEnv */*env*/, jobject /*ja reinterpret_cast<InputStreamThread*>(qtObject)->javaReadyRead(buffer, bufferLength); } -void QtBluetoothLE_leScanResult(JNIEnv *env, jobject, jlong qtObject, jobject bluetoothDevice, jint rssi) +void QtBluetoothLE_leScanResult(JNIEnv *env, jobject, jlong qtObject, jobject bluetoothDevice, + jint rssi, jbyteArray scanRecord) { reinterpret_cast<AndroidBroadcastReceiver*>(qtObject)->onReceiveLeScan( - env, bluetoothDevice, rssi); + env, bluetoothDevice, rssi, + scanRecord); } @@ -203,7 +205,7 @@ static JNINativeMethod methods[] = { }; static JNINativeMethod methods_le[] = { - {"leScanResult", "(JLandroid/bluetooth/BluetoothDevice;I)V", + {"leScanResult", "(JLandroid/bluetooth/BluetoothDevice;I[B)V", (void *) QtBluetoothLE_leScanResult}, {"leConnectionStateChange", "(JII)V", (void *) LowEnergyNotificationHub::lowEnergy_connectionChange}, diff --git a/src/bluetooth/android/localdevicebroadcastreceiver_p.h b/src/bluetooth/android/localdevicebroadcastreceiver_p.h index 90f40333..261bf29d 100644 --- a/src/bluetooth/android/localdevicebroadcastreceiver_p.h +++ b/src/bluetooth/android/localdevicebroadcastreceiver_p.h @@ -64,7 +64,7 @@ public: explicit LocalDeviceBroadcastReceiver(QObject *parent = 0); virtual ~LocalDeviceBroadcastReceiver() {} virtual void onReceive(JNIEnv *env, jobject context, jobject intent); - virtual void onReceiveLeScan(JNIEnv *, jobject, jint) {} + virtual void onReceiveLeScan(JNIEnv *, jobject, jint, jbyteArray) {} bool pairingConfirmation(bool accept); signals: diff --git a/src/bluetooth/android/servicediscoverybroadcastreceiver_p.h b/src/bluetooth/android/servicediscoverybroadcastreceiver_p.h index f0abf511..a93cbd3f 100644 --- a/src/bluetooth/android/servicediscoverybroadcastreceiver_p.h +++ b/src/bluetooth/android/servicediscoverybroadcastreceiver_p.h @@ -66,7 +66,7 @@ class ServiceDiscoveryBroadcastReceiver : public AndroidBroadcastReceiver public: ServiceDiscoveryBroadcastReceiver(QObject* parent = 0); virtual void onReceive(JNIEnv *env, jobject context, jobject intent); - virtual void onReceiveLeScan(JNIEnv *, jobject, jint) {} + virtual void onReceiveLeScan(JNIEnv *, jobject, jint, jbyteArray) {} static QList<QBluetoothUuid> convertParcelableArray(const QAndroidJniObject &obj); diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp index 411e7a2b..2d6e64be 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp @@ -69,9 +69,17 @@ QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate( lowEnergySearchTimeout(25000), q_ptr(parent) { + QAndroidJniEnvironment env; adapter = QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter", "getDefaultAdapter", "()Landroid/bluetooth/BluetoothAdapter;"); + if (!adapter.isValid()) { + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth"; + } } QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate() diff --git a/src/bluetooth/qlowenergycontroller.cpp b/src/bluetooth/qlowenergycontroller.cpp index 2b28a873..4df92a39 100644 --- a/src/bluetooth/qlowenergycontroller.cpp +++ b/src/bluetooth/qlowenergycontroller.cpp @@ -635,6 +635,23 @@ QBluetoothAddress QLowEnergyController::remoteAddress() const } /*! + Returns the unique identifier of the remote Bluetooth Low Energy device. + + On macOS/iOS/tvOS CoreBluetooth does not expose/accept hardware addresses for + LE devices; instead developers are supposed to use unique 128-bit UUIDs, generated + by CoreBluetooth. These UUIDS will stay constant for the same central <-> peripheral + pair and we use them when connecting to a remote device. For a controller in the + \l CentralRole, this value will always be the one passed in when the controller + object was created. For a controller in the \l PeripheralRole, this value is invalid. + + \since 5.8 + */ +QBluetoothUuid QLowEnergyController::remoteDeviceUuid() const +{ + return QBluetoothUuid(); +} + +/*! Returns the name of the remote Bluetooth Low Energy device, if the controller is in the \l CentralRole. Otherwise the result is unspecified. @@ -825,7 +842,10 @@ QLowEnergyService *QLowEnergyController::createServiceObject( also starts listening for incoming client connections. Providing \a scanResponseData is not required, as it is not applicable for certain - configurations of \c parameters. + configurations of \c parameters. \a advertisingData and \a scanResponseData are limited + to 31 byte user data. If, for example, several 128bit uuids are added to \a advertisingData, + the advertised packets may not contain all uuids. The existing limit may have caused the truncation + of uuids. In such cases \a scanResponseData may be used for additional information. If this object is currently not in the \l UnconnectedState, nothing happens. \note Advertising will stop automatically once a client connects to the local device. diff --git a/src/bluetooth/qlowenergycontroller.h b/src/bluetooth/qlowenergycontroller.h index 4ee07531..1c4fa83f 100644 --- a/src/bluetooth/qlowenergycontroller.h +++ b/src/bluetooth/qlowenergycontroller.h @@ -107,6 +107,7 @@ public: QBluetoothAddress localAddress() const; QBluetoothAddress remoteAddress() const; + QBluetoothUuid remoteDeviceUuid() const; QString remoteName() const; diff --git a/src/bluetooth/qlowenergycontroller_osx.mm b/src/bluetooth/qlowenergycontroller_osx.mm index f2b7b0bd..80ef72af 100644 --- a/src/bluetooth/qlowenergycontroller_osx.mm +++ b/src/bluetooth/qlowenergycontroller_osx.mm @@ -1098,6 +1098,13 @@ QBluetoothAddress QLowEnergyController::remoteAddress() const return osx_d_ptr->remoteAddress; } +QBluetoothUuid QLowEnergyController::remoteDeviceUuid() const +{ + OSX_D_PTR; + + return osx_d_ptr->deviceUuid; +} + QString QLowEnergyController::remoteName() const { OSX_D_PTR; diff --git a/src/nfc/nfc.pro b/src/nfc/nfc.pro index 8e737dd5..0819cc4f 100644 --- a/src/nfc/nfc.pro +++ b/src/nfc/nfc.pro @@ -80,6 +80,7 @@ linux:!android:qtHaveModule(dbus) { } else:android { NFC_BACKEND_AVAILABLE = yes + DEFINES += QT_ANDROID_NFC ANDROID_PERMISSIONS = \ android.permission.NFC ANDROID_BUNDLED_JAR_DEPENDENCIES = \ diff --git a/src/nfc/qllcpserver.cpp b/src/nfc/qllcpserver.cpp index 2bf2a097..66831b9f 100644 --- a/src/nfc/qllcpserver.cpp +++ b/src/nfc/qllcpserver.cpp @@ -41,6 +41,8 @@ #if defined(QT_SIMULATOR) #include "qllcpserver_simulator_p.h" +#elif defined(QT_ANDROID_NFC) +#include "qllcpserver_android_p.h" #else #include "qllcpserver_p_p.h" #endif |