diff options
Diffstat (limited to 'src/bluetooth/android/jni_android.cpp')
-rw-r--r-- | src/bluetooth/android/jni_android.cpp | 171 |
1 files changed, 168 insertions, 3 deletions
diff --git a/src/bluetooth/android/jni_android.cpp b/src/bluetooth/android/jni_android.cpp index eb1fc2dd..ebc46a7c 100644 --- a/src/bluetooth/android/jni_android.cpp +++ b/src/bluetooth/android/jni_android.cpp @@ -44,20 +44,171 @@ #include <android/log.h> #include <QtCore/QLoggingCategory> #include <QtBluetooth/qbluetoothglobal.h> -#include <QtAndroidExtras/QAndroidJniObject> +#include "android/jni_android_p.h" #include "android/androidbroadcastreceiver_p.h" +#include "android/serveracceptancethread_p.h" +#include "android/inputstreamthread_p.h" Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID) +typedef QHash<QByteArray, QAndroidJniObject> JCachedStringFields; +Q_GLOBAL_STATIC(JCachedStringFields, cachedStringFields) + +//Java class names +static const char * const javaBluetoothAdapterClassName = "android/bluetooth/BluetoothAdapter"; +static const char * const javaBluetoothDeviceClassName = "android/bluetooth/BluetoothDevice" ; + +//Java field names +static const char * const javaActionAclConnected = "ACTION_ACL_CONNECTED"; +static const char * const javaActionAclDisconnected = "ACTION_ACL_DISCONNECTED"; +static const char * const javaActionBondStateChanged = "ACTION_BOND_STATE_CHANGED"; +static const char * const javaActionDiscoveryStarted = "ACTION_DISCOVERY_STARTED"; +static const char * const javaActionDiscoveryFinished = "ACTION_DISCOVERY_FINISHED"; +static const char * const javaActionFound = "ACTION_FOUND"; +static const char * const javaActionPairingRequest = "ACTION_PAIRING_REQUEST"; +static const char * const javaActionScanModeChanged = "ACTION_SCAN_MODE_CHANGED"; +static const char * const javaActionUuid = "ACTION_UUID"; +static const char * const javaExtraBondState = "EXTRA_BOND_STATE"; +static const char * const javaExtraDevice = "EXTRA_DEVICE"; +static const char * const javaExtraPairingKey = "EXTRA_PAIRING_KEY"; +static const char * const javaExtraPairingVariant = "EXTRA_PAIRING_VARIANT"; +static const char * const javaExtraRssi = "EXTRA_RSSI"; +static const char * const javaExtraScanMode = "EXTRA_SCAN_MODE"; +static const char * const javaExtraUuid = "EXTRA_UUID"; + +/* + * This function operates on the assumption that each + * field is of type java/lang/String. + */ +QAndroidJniObject valueForStaticField(JavaNames javaName, JavaNames javaFieldName) +{ + //construct key + //the switch statements are used to reduce the number of duplicated strings + //in the library + + const char* className; + switch (javaName) { + case JavaNames::BluetoothAdapter: + className = javaBluetoothAdapterClassName; break; + case JavaNames::BluetoothDevice: + className = javaBluetoothDeviceClassName; break; + default: + qWarning(QT_BT_ANDROID) << "Unknown java class name passed to valueForStaticField():" << javaName; + return QAndroidJniObject(); + } + + const char *fieldName; + switch (javaFieldName) { + case JavaNames::ActionAclConnected: + fieldName = javaActionAclConnected; break; + case JavaNames::ActionAclDisconnected: + fieldName = javaActionAclDisconnected; break; + case JavaNames::ActionBondStateChanged: + fieldName = javaActionBondStateChanged; break; + case JavaNames::ActionDiscoveryStarted: + fieldName = javaActionDiscoveryStarted; break; + case JavaNames::ActionDiscoveryFinished: + fieldName = javaActionDiscoveryFinished; break; + case JavaNames::ActionFound: + fieldName = javaActionFound; break; + case JavaNames::ActionPairingRequest: + fieldName = javaActionPairingRequest; break; + case JavaNames::ActionScanModeChanged: + fieldName = javaActionScanModeChanged; break; + case JavaNames::ActionUuid: + fieldName = javaActionUuid; break; + case JavaNames::ExtraBondState: + fieldName = javaExtraBondState; break; + case JavaNames::ExtraDevice: + fieldName = javaExtraDevice; break; + case JavaNames::ExtraPairingKey: + fieldName = javaExtraPairingKey; break; + case JavaNames::ExtraPairingVariant: + fieldName = javaExtraPairingVariant; break; + case JavaNames::ExtraRssi: + fieldName = javaExtraRssi; break; + case JavaNames::ExtraScanMode: + fieldName = javaExtraScanMode; break; + case JavaNames::ExtraUuid: + fieldName = javaExtraUuid; break; + default: + qWarning(QT_BT_ANDROID) << "Unknown java field name passed to valueForStaticField():" << javaFieldName; + return QAndroidJniObject(); + } + + int offset_class = qstrlen(className); + int offset_field = qstrlen(fieldName); + QByteArray key(offset_class + offset_field, Qt::Uninitialized); + memcpy(key.data(), className, offset_class); + memcpy(key.data()+offset_class, fieldName, offset_field); + + JCachedStringFields::iterator it = cachedStringFields()->find(key); + if (it == cachedStringFields()->end()) { + QAndroidJniEnvironment env; + QAndroidJniObject fieldValue = QAndroidJniObject::getStaticObjectField( + className, fieldName, "Ljava/lang/String;"); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + cachedStringFields()->insert(key, QAndroidJniObject()); + return QAndroidJniObject(); + } + + cachedStringFields()->insert(key, fieldValue); + return fieldValue; + } else { + return it.value(); + } +} + void QtBroadcastReceiver_jniOnReceive(JNIEnv *env, jobject /*javaObject*/, jlong qtObject, jobject context, jobject intent) { reinterpret_cast<AndroidBroadcastReceiver*>(qtObject)->onReceive(env, context, intent); } +static void QtBluetoothSocketServer_errorOccurred(JNIEnv */*env*/, jobject /*javaObject*/, + jlong qtObject, jint errorCode) +{ + reinterpret_cast<ServerAcceptanceThread*>(qtObject)->javaThreadErrorOccurred(errorCode); +} + +static void QtBluetoothSocketServer_newSocket(JNIEnv */*env*/, jobject /*javaObject*/, + jlong qtObject, jobject socket) +{ + reinterpret_cast<ServerAcceptanceThread*>(qtObject)->javaNewSocket(socket); +} + +static void QtBluetoothInputStreamThread_errorOccurred(JNIEnv */*env*/, jobject /*javaObject*/, + jlong qtObject, jint errorCode) +{ + reinterpret_cast<InputStreamThread*>(qtObject)->javaThreadErrorOccurred(errorCode); +} + +static void QtBluetoothInputStreamThread_readyData(JNIEnv */*env*/, jobject /*javaObject*/, + jlong qtObject, jbyteArray buffer, jint bufferLength) +{ + reinterpret_cast<InputStreamThread*>(qtObject)->javaReadyRead(buffer, bufferLength); +} + + static JNINativeMethod methods[] = { {"jniOnReceive", "(JLandroid/content/Context;Landroid/content/Intent;)V", - (void *) QtBroadcastReceiver_jniOnReceive}, + (void *) QtBroadcastReceiver_jniOnReceive}, +}; + +static JNINativeMethod methods_server[] = { + {"errorOccurred", "(JI)V", + (void *) QtBluetoothSocketServer_errorOccurred}, + {"newSocket", "(JLandroid/bluetooth/BluetoothSocket;)V", + (void *) QtBluetoothSocketServer_newSocket}, +}; + +static JNINativeMethod methods_inputStream[] = { + {"errorOccurred", "(JI)V", + (void *) QtBluetoothInputStreamThread_errorOccurred}, + {"readyData", "(J[BI)V", + (void *) QtBluetoothInputStreamThread_readyData}, }; static const char logTag[] = "QtBluetooth"; @@ -75,8 +226,22 @@ static bool registerNatives(JNIEnv *env) jclass clazz; FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver"); + if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) { - __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives failed"); + __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives for BraodcastReceiver failed"); + return false; + } + + FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer"); + if (env->RegisterNatives(clazz, methods_server, sizeof(methods_server) / sizeof(methods_server[0])) < 0) { + __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives for SocketServer failed"); + return false; + } + + FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/bluetooth/QtBluetoothInputStreamThread"); + if (env->RegisterNatives(clazz, methods_inputStream, + sizeof(methods_inputStream) / sizeof(methods_inputStream[0])) < 0) { + __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives for InputStreamThread failed"); return false; } |