diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-08-28 16:22:31 +0200 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-08-28 16:22:31 +0200 |
commit | 8146a18be0c98751816ffe40661308081a57573d (patch) | |
tree | 69a2ddc07bad88df0d27d6b9a33ebb1ac522b71a /src/bluetooth/qbluetoothsocket_android.cpp | |
parent | 9f4c45b58b82b59740dc60e22cba6894efd6c164 (diff) | |
parent | 167faeec86ed4d9c9f099f5180784c7b0cb9aa42 (diff) |
Merge remote-tracking branch 'origin/5.3' into 5.4
Conflicts:
src/bluetooth/qbluetoothdevicediscoveryagent_p.cpp
Change-Id: Ie8bf1903f9c7c1ccd5b05a3f97049ae0882b88b8
Diffstat (limited to 'src/bluetooth/qbluetoothsocket_android.cpp')
-rw-r--r-- | src/bluetooth/qbluetoothsocket_android.cpp | 138 |
1 files changed, 126 insertions, 12 deletions
diff --git a/src/bluetooth/qbluetoothsocket_android.cpp b/src/bluetooth/qbluetoothsocket_android.cpp index c98e66dd..ce68d236 100644 --- a/src/bluetooth/qbluetoothsocket_android.cpp +++ b/src/bluetooth/qbluetoothsocket_android.cpp @@ -76,16 +76,127 @@ bool QBluetoothSocketPrivate::ensureNativeSocket(QBluetoothServiceInfo::Protocol void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid, - QIODevice::OpenMode openMode) + QIODevice::OpenMode openMode, + int fallbackServiceChannel) { Q_Q(QBluetoothSocket); q->setSocketState(QBluetoothSocket::ConnectingState); - QtConcurrent::run(this, &QBluetoothSocketPrivate::connectToServiceConc, address, uuid, openMode); + QtConcurrent::run(this, &QBluetoothSocketPrivate::connectToServiceConc, + address, uuid, openMode, fallbackServiceChannel); +} + +bool QBluetoothSocketPrivate::fallBackConnect(QAndroidJniObject uuid, int channel) +{ + 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)); + 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) { + qCWarning(QT_BT_ANDROID) << "Could not get Integer.TYPE"; + return false; + } + + jobjectArray paramTypes = env->NewObjectArray(1, classClass, integerObject); + if (!paramTypes) { + qCWarning(QT_BT_ANDROID) << "Could not create new Class[]{Integer.TYPE}"; + return false; + } + + QAndroidJniObject parcelUuid("android/os/ParcelUuid", "(Ljava/util/UUID;)V", + uuid.object()); + if (parcelUuid.isValid()) { + jint socketChannel = remoteDevice.callMethod<jint>("getServiceChannel", + "(Landroid/os/ParcelUuid;)I", + parcelUuid.object()); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + + if (socketChannel + == remoteDevice.getStaticField<jint>("android/bluetooth/BluetoothDevice", "ERROR")) { + qCWarning(QT_BT_ANDROID) << "Cannot determine RFCOMM service channel."; + } else { + qCWarning(QT_BT_ANDROID) << "Using found rfcomm channel" << socketChannel; + channel = socketChannel; + } + } + + QAndroidJniObject method = remoteDeviceClass.callObjectMethod( + "getMethod", + "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", + QAndroidJniObject::fromString(QLatin1String("createRfcommSocket")).object<jstring>(), + paramTypes); + if (!method.isValid() || env->ExceptionCheck()) { + qCWarning(QT_BT_ANDROID) << "Could not invoke getMethod"; + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + 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; + } + + 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) + { + qCWarning(QT_BT_ANDROID) << "Invoke Resulted with error."; + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + return false; + } + + socketObject = QAndroidJniObject(invokeResult); + socketObject.callMethod<void>("connect"); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + + qCWarning(QT_BT_ANDROID) << "Socket connect via workaround failed."; + + return false; + } + + qCWarning(QT_BT_ANDROID) << "Workaround invoked."; + return true; } void QBluetoothSocketPrivate::connectToServiceConc(const QBluetoothAddress &address, - const QBluetoothUuid &uuid, QIODevice::OpenMode openMode) + const QBluetoothUuid &uuid, QIODevice::OpenMode openMode, int fallbackServiceChannel) { Q_Q(QBluetoothSocket); Q_UNUSED(openMode); @@ -152,16 +263,19 @@ void QBluetoothSocketPrivate::connectToServiceConc(const QBluetoothAddress &addr socketObject.callMethod<void>("connect"); if (env->ExceptionCheck()) { - if (env->ExceptionCheck()) { - env->ExceptionDescribe(); - env->ExceptionClear(); - } + env->ExceptionDescribe(); + env->ExceptionClear(); - socketObject = remoteDevice = QAndroidJniObject(); - errorString = QBluetoothSocket::tr("Connection to service failed"); - q->setSocketError(QBluetoothSocket::ServiceNotFoundError); - q->setSocketState(QBluetoothSocket::UnconnectedState); - return; + bool success = fallBackConnect(uuidObject, fallbackServiceChannel); + if (!success) { + errorString = QBluetoothSocket::tr("Connection to service failed"); + socketObject = remoteDevice = QAndroidJniObject(); + q->setSocketError(QBluetoothSocket::ServiceNotFoundError); + q->setSocketState(QBluetoothSocket::UnconnectedState); + + env->ExceptionClear(); //just in case + return; + } } if (inputThread) { |