6#include <QCoreApplication>
7#include <QtCore/QtEndian>
8#include <QtCore/QLoggingCategory>
9#include <QtBluetooth/QBluetoothAddress>
10#include <QtBluetooth/QBluetoothDeviceInfo>
11#include <QtBluetooth/QBluetoothUuid>
13#include <QtCore/QHash>
14#include <QtCore/qbitarray.h>
31 const qsizetype numberOfMajorDeviceClasses = 11;
49 qCWarning(QT_BT_ANDROID) <<
"Unknown category of major device class:" << classes;
52 return QBitArray(numberOfMajorDeviceClasses,
false);
59static const
char javaBluetoothDeviceClassName[] = "android/bluetooth/BluetoothDevice";
71 const char javaFieldName[14];
228 for (
int i = 0;
i < 16;
i++)
235 const JCachedBtTypes::iterator
it = cachedBtTypes()->
find(javaType);
236 if (
it == cachedBtTypes()->
end()) {
238 if (javaType == QJniObject::getStaticField<jint>(
240 cachedBtTypes()->insert(javaType,
243 }
else if (javaType == QJniObject::getStaticField<jint>(
245 cachedBtTypes()->insert(javaType,
248 }
else if (javaType == QJniObject::getStaticField<jint>(
250 cachedBtTypes()->insert(javaType,
253 }
else if (javaType == QJniObject::getStaticField<jint>(
255 cachedBtTypes()->insert(javaType,
258 qCWarning(QT_BT_ANDROID) <<
"Unknown Bluetooth device type value";
270 if (
it == cachedMajorTypes()->
end()) {
277 auto fieldId = env->GetStaticFieldID(clazz, majorMapping.javaFieldName,
"I");
278 if (!env->ExceptionCheck())
279 fieldValue = env->GetStaticIntField(clazz, fieldId);
280 if (env.checkAndClearExceptions()) {
281 qCWarning(QT_BT_ANDROID) <<
"Unknown BluetoothClass.Device.Major field" << javaType;
286 cachedMajorTypes()->insert(fieldValue, majorMapping.qtMajor);
289 if (fieldValue == javaType)
290 result = majorMapping.qtMajor;
305 int mappingIndex = (int) major;
324 jint fieldValue = QJniObject::getStaticField<jint>(
328 cachedMinorTypes()->insert(fieldValue,
minorMappings[sizeIndex].qtMinor);
332 initializedCacheTracker()->setBit(mappingIndex);
346 if (!initializedCacheTracker()->
at(mappingIndex))
350 if (
it == cachedMinorTypes()->
end())
359 addAction(valueForStaticField<QtJniTypes::BluetoothDevice, JavaNames::ActionFound>());
360 addAction(valueForStaticField<QtJniTypes::BluetoothAdapter, JavaNames::ActionDiscoveryStarted>());
361 addAction(valueForStaticField<QtJniTypes::BluetoothAdapter, JavaNames::ActionDiscoveryFinished>());
371 const QString action = intentObject.callMethod<jstring>(
"getAction").
toString();
373 qCDebug(QT_BT_ANDROID) <<
"DeviceDiscoveryBroadcastReceiver::onReceive() - event:" << action;
387 intentObject.callMethod<QtJniTypes::Parcelable>(
"getParcelableExtra",
388 keyExtra.object<jstring>());
390 if (!bluetoothDevice.isValid())
395 int rssi = intentObject.callMethod<jshort>(
"getShortExtra",
396 keyExtra.object<jstring>(), jshort(0));
406 JNIEnv *, jobject jBluetoothDevice, jint
rssi, jbyteArray scanRecord)
408 const QJniObject bluetoothDevice(jBluetoothDevice);
409 if (!bluetoothDevice.isValid())
419 const QString deviceName = bluetoothDevice.callMethod<jstring>(
"getName").
toString();
421 bluetoothDevice.callMethod<jstring>(
"getAddress").toString());
423 bluetoothDevice.callMethod<QtJniTypes::BluetoothClass>(
"getBluetoothClass");
425 if (!bluetoothClass.isValid())
429 bluetoothClass.callMethod<jint>(
"getMajorDeviceClass"));
433 jint javaMinor = bluetoothClass.callMethod<jint>(
"getDeviceClass");
437 classType |= ((
quint32(minorDeviceType) & 0x3f) << 2);
453 int androidId = (current << 16);
454 if (bluetoothClass.callMethod<jboolean>(
"hasService", androidId))
455 serviceResult |= current;
459 classType |= (serviceResult << 13);
464 if (scanRecord !=
nullptr) {
467 jbyte *elems = env->GetByteArrayElements(scanRecord, &isCopy);
468 const char *scanRecordBuffer =
reinterpret_cast<const char *
>(elems);
469 const jsize scanRecordLength = env->GetArrayLength(scanRecord);
476 while (
i < scanRecordLength) {
480 const int nBytes = scanRecordBuffer[
i];
484 if (
i >= scanRecordLength - nBytes)
487 const int adType = scanRecordBuffer[
i+1];
488 const char *dataPtr = &scanRecordBuffer[
i+2];
494 foundService =
QBluetoothUuid(qFromLittleEndian<quint16>(dataPtr));
498 foundService =
QBluetoothUuid(qFromLittleEndian<quint32>(dataPtr));
503 QBluetoothUuid(qToBigEndian<QUuid::Id128Bytes>(qFromLittleEndian<QUuid::Id128Bytes>(dataPtr)));
520 qFromLittleEndian<QUuid::Id128Bytes>(dataPtr))),
526 info.setManufacturerData(qFromLittleEndian<quint16>(dataPtr),
548 if (!foundService.
isNull() && !serviceUuids.
contains(foundService))
549 serviceUuids.
append(foundService);
552 if (
info.name().isEmpty())
553 info.setName(localName);
555 info.setServiceUuids(serviceUuids);
557 env->ReleaseByteArrayElements(scanRecord, elems, JNI_ABORT);
560 auto methodId = env.findMethod(bluetoothDevice.objectClass(),
"getType",
"()I");
561 jint javaBtType = env->CallIntMethod(bluetoothDevice.object(), methodId);
562 if (!env.checkAndClearExceptions()) {
std::vector< ObjCStrongReference< CBMutableService > > services
void addAction(const QJniObject &filter)
virtual void onReceiveLeScan(JNIEnv *env, jobject jBluetoothDevice, jint rssi, jbyteArray scanRecord)
virtual void onReceive(JNIEnv *env, jobject context, jobject intent)
DeviceDiscoveryBroadcastReceiver(QObject *parent=nullptr)
void deviceDiscovered(const QBluetoothDeviceInfo &info, bool isLeScanResult)
@ WiredModemOrVoiceGatewayPhone
@ UncategorizedWearableDevice
@ UncategorizedHealthDevice
@ HealthBloodPressureMonitor
@ KeyboardWithPointingDevicePeripheral
@ UncategorizedPeripheral
@ PointingDevicePeripheral
@ BaseRateAndLowEnergyCoreConfiguration
@ LowEnergyCoreConfiguration
@ UnknownCoreConfiguration
@ BaseRateCoreConfiguration
MajorDeviceClass
This enum describes a Bluetooth device's major device class.
@ HandheldClamShellComputer
@ UncategorizedAudioVideoDevice
@ VideoDisplayAndLoudspeaker
void append(parameter_type t)
iterator find(const T &value)
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
bool isNull() const noexcept
Returns true if this is the null UUID {00000000-0000-0000-0000-000000000000}; otherwise returns false...
static QBitArray initializeMinorCaches()
static const char javaBluetoothClassDeviceClassName[]
static constexpr quint8 minorIndexSizes[]
static const char javaDeviceTypeLE[]
static const char javaDeviceTypeDual[]
static constexpr MajorClassJavaToQtMapping majorMappings[]
static const char javaDeviceTypeUnknown[]
int mappingIndexForMajor(QBluetoothDeviceInfo::MajorDeviceClass major)
static const char javaDeviceTypeClassic[]
QBluetoothDeviceInfo::MajorDeviceClass resolveAndroidMajorClass(jint javaType)
static const char javaBluetoothClassDeviceMajorClassName[]
quint8 resolveAndroidMinorClass(QBluetoothDeviceInfo::MajorDeviceClass major, jint javaMinor)
QT_BEGIN_NAMESPACE typedef QHash< jint, QBluetoothDeviceInfo::CoreConfigurations > JCachedBtTypes
QUuid::Id128Bytes qbswap(const QUuid::Id128Bytes src)
static const MinorClassJavaToQtMapping minorMappings[]
@ ADType16BitUuidComplete
@ ADTypeShortenedLocalName
@ ADType32BitUuidIncomplete
@ ADTypeManufacturerSpecificData
@ ADType128BitUuidIncomplete
@ ADType16BitUuidIncomplete
@ ADTypeCompleteLocalName
@ ADType32BitUuidComplete
@ ADType128BitUuidComplete
@ ADTypeServiceData128Bit
void triggerCachingOfMinorsForMajor(QBluetoothDeviceInfo::MajorDeviceClass major)
QBluetoothDeviceInfo::CoreConfigurations qtBtTypeForJavaBtType(jint javaType)
QSet< QString >::iterator it
@ ActionDiscoveryFinished
QJniObject valueForStaticField()
Combined button and popup list for selecting options.
#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS)
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
QFileInfo info(fileName)
[8]
char * toString(const MyType &t)
[31]
QBluetoothDeviceInfo::MajorDeviceClass qtMajor
char const * javaFieldName
bool contains(const AT &t) const noexcept
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent