summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/android/jni_android.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/bluetooth/android/jni_android.cpp')
-rw-r--r--src/bluetooth/android/jni_android.cpp171
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;
}