diff options
-rw-r--r-- | src/bluetooth/qbluetoothsocket_android.cpp | 236 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothsocket_p.h | 7 |
2 files changed, 121 insertions, 122 deletions
diff --git a/src/bluetooth/qbluetoothsocket_android.cpp b/src/bluetooth/qbluetoothsocket_android.cpp index 2738a92d..8d9cba2a 100644 --- a/src/bluetooth/qbluetoothsocket_android.cpp +++ b/src/bluetooth/qbluetoothsocket_android.cpp @@ -90,7 +90,117 @@ void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address, Q_Q(QBluetoothSocket); q->setSocketState(QBluetoothSocket::ConnectingState); - QtConcurrent::run(this, &QBluetoothSocketPrivate::connectToServiceConc, address, uuid, openMode, fallbackServiceChannel); + 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, @@ -161,131 +271,17 @@ void QBluetoothSocketPrivate::connectToServiceConc(const QBluetoothAddress &addr socketObject.callMethod<void>("connect"); if (env->ExceptionCheck()) { - if (env->ExceptionCheck()) { - env->ExceptionDescribe(); - env->ExceptionClear(); - } - - qCWarning(QT_BT_ANDROID) << "Falling back to workaround."; - - jclass remoteDeviceClazz = env->GetObjectClass(remoteDevice.object()); - jmethodID getClassMethod = env->GetMethodID(remoteDeviceClazz, "getClass", "()Ljava/lang/Class;"); - if (!getClassMethod) { - qCWarning(QT_BT_ANDROID) << "getClass method could not found."; - - errorString = QBluetoothSocket::tr("Connection to service failed"); - - socketObject = remoteDevice = QAndroidJniObject(); - q->setSocketError(QBluetoothSocket::ServiceNotFoundError); - q->setSocketState(QBluetoothSocket::UnconnectedState); - return; - } - - QAndroidJniObject remoteDeviceClass = QAndroidJniObject(env->CallObjectMethod(remoteDevice.object(), getClassMethod)); - if (!remoteDeviceClass.isValid()) { - qCWarning(QT_BT_ANDROID) << "Could not invoke getClass from BluetoothDevice."; - - errorString = QBluetoothSocket::tr("Connection to service failed"); - - socketObject = remoteDevice = QAndroidJniObject(); - q->setSocketError(QBluetoothSocket::ServiceNotFoundError); - q->setSocketState(QBluetoothSocket::UnconnectedState); - return; - } - - 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"; - - socketObject = remoteDevice = QAndroidJniObject(); - q->setSocketError(QBluetoothSocket::ServiceNotFoundError); - q->setSocketState(QBluetoothSocket::UnconnectedState); - return; - } - - jobjectArray paramTypes = env->NewObjectArray(1, classClass, integerObject); - if (!paramTypes) { - qCWarning(QT_BT_ANDROID) << "Could not create new Class[]{Integer.TYPE}"; - - errorString = QBluetoothSocket::tr("Connection to service failed"); - - socketObject = remoteDevice = QAndroidJniObject(); - q->setSocketError(QBluetoothSocket::ServiceNotFoundError); - q->setSocketState(QBluetoothSocket::UnconnectedState); - return; - } - - 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(); - } + env->ExceptionDescribe(); + env->ExceptionClear(); + 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); - return; - } - - 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."; - - socketObject = remoteDevice = QAndroidJniObject(); - q->setSocketError(QBluetoothSocket::ServiceNotFoundError); - q->setSocketState(QBluetoothSocket::UnconnectedState); - return; - } - - 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, fallbackServiceChannel)); - - 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(); - } - socketObject = remoteDevice = QAndroidJniObject(); q->setSocketError(QBluetoothSocket::ServiceNotFoundError); q->setSocketState(QBluetoothSocket::UnconnectedState); - return; - } - - socketObject = QAndroidJniObject(invokeResult); - socketObject.callMethod<void>("connect"); - if (env->ExceptionCheck() || socketObject.callMethod<jboolean>("isConnected") == JNI_FALSE) - { - if (env->ExceptionCheck()) - { - env->ExceptionDescribe(); - env->ExceptionClear(); - } - - errorString = QBluetoothSocket::tr("Connection to service failed"); - socketObject = remoteDevice = QAndroidJniObject(); - q->setSocketError(QBluetoothSocket::ServiceNotFoundError); - q->setSocketState(QBluetoothSocket::UnconnectedState); + env->ExceptionClear(); //just in case return; } } diff --git a/src/bluetooth/qbluetoothsocket_p.h b/src/bluetooth/qbluetoothsocket_p.h index cde9d33b..bef11327 100644 --- a/src/bluetooth/qbluetoothsocket_p.h +++ b/src/bluetooth/qbluetoothsocket_p.h @@ -98,12 +98,15 @@ public: #if defined(QT_QNX_BLUETOOTH) void connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid, QIODevice::OpenMode openMode); #elif defined(QT_ANDROID_BLUETOOTH) - void connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid, QIODevice::OpenMode openMode, int fallbackServiceChannel = 1); + void connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid, + QIODevice::OpenMode openMode, int fallbackServiceChannel = 1); + bool fallBackConnect(QAndroidJniObject uuid, int channel); #else void connectToService(const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode); #endif #ifdef QT_ANDROID_BLUETOOTH - void connectToServiceConc(const QBluetoothAddress &address, const QBluetoothUuid &uuid, QIODevice::OpenMode openMode, int fallbackServiceChannel = 1); + void connectToServiceConc(const QBluetoothAddress &address, const QBluetoothUuid &uuid, + QIODevice::OpenMode openMode, int fallbackServiceChannel = 1); #endif |