Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
jni_android.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
2// Copyright (C) 2016 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include <jni.h>
6#include <android/log.h>
7#include <QtCore/QLoggingCategory>
8#include <QtBluetooth/qtbluetoothglobal.h>
9#include "android/jni_android_p.h"
10#include "android/androidbroadcastreceiver_p.h"
11#include "android/serveracceptancethread_p.h"
12#include "android/inputstreamthread_p.h"
13#include "android/lowenergynotificationhub_p.h"
14
16
17Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
18
19typedef QHash<QByteArray, QString> JCachedStringFields;
20Q_GLOBAL_STATIC(JCachedStringFields, cachedStringFields)
21Q_GLOBAL_STATIC(QMutex, stringCacheMutex);
22
23/*
24 * This function operates on the assumption that each
25 * field is of type java/lang/String.
26 */
27QString valueFromStaticFieldCache(const char *key, const char *className, const char *fieldName)
28{
29 QMutexLocker lock(stringCacheMutex());
30 JCachedStringFields::iterator it = cachedStringFields()->find(key);
31 if (it == cachedStringFields()->end()) {
32 QJniEnvironment env;
33 QJniObject fieldValue = QJniObject::getStaticObjectField(
34 className, fieldName, "Ljava/lang/String;");
35 if (!fieldValue.isValid()) {
36 cachedStringFields()->insert(key, {});
37 return {};
38 }
39 const QString string = fieldValue.toString();
40 cachedStringFields()->insert(key, string);
41 return string;
42 } else {
43 return it.value();
44 }
45}
46
47void QtBroadcastReceiver_jniOnReceive(JNIEnv *env, jobject /*javaObject*/,
48 jlong qtObject, QtJniTypes::Context context,
49 QtJniTypes::Intent intent)
50{
51 reinterpret_cast<AndroidBroadcastReceiver*>(qtObject)->onReceive(env, context.object(), intent.object());
52}
53Q_DECLARE_JNI_NATIVE_METHOD(QtBroadcastReceiver_jniOnReceive, jniOnReceive)
54
55static void QtBluetoothSocketServer_errorOccurred(JNIEnv */*env*/, jobject /*javaObject*/,
56 jlong qtObject, jint errorCode)
57{
58 reinterpret_cast<ServerAcceptanceThread*>(qtObject)->javaThreadErrorOccurred(errorCode);
59}
60Q_DECLARE_JNI_NATIVE_METHOD(QtBluetoothSocketServer_errorOccurred, errorOccurred)
61
62static void QtBluetoothSocketServer_newSocket(JNIEnv */*env*/, jobject /*javaObject*/,
63 jlong qtObject, QtJniTypes::BluetoothSocket socket)
64{
65 reinterpret_cast<ServerAcceptanceThread*>(qtObject)->javaNewSocket(socket.object());
66}
67Q_DECLARE_JNI_NATIVE_METHOD(QtBluetoothSocketServer_newSocket, newSocket)
68
69static void QtBluetoothInputStreamThread_errorOccurred(JNIEnv */*env*/, jobject /*javaObject*/,
70 jlong qtObject, jint errorCode)
71{
72 reinterpret_cast<InputStreamThread*>(qtObject)->javaThreadErrorOccurred(errorCode);
73}
74Q_DECLARE_JNI_NATIVE_METHOD(QtBluetoothInputStreamThread_errorOccurred, errorOccurred)
75
76static void QtBluetoothInputStreamThread_readyData(JNIEnv */*env*/, jobject /*javaObject*/,
77 jlong qtObject, jbyteArray buffer, jint bufferLength)
78{
79 reinterpret_cast<InputStreamThread*>(qtObject)->javaReadyRead(buffer, bufferLength);
80}
81Q_DECLARE_JNI_NATIVE_METHOD(QtBluetoothInputStreamThread_readyData, readyData)
82
83void QtBluetoothLE_leScanResult(JNIEnv *env, jobject, jlong qtObject,
84 QtJniTypes::BluetoothDevice bluetoothDevice, jint rssi,
85 jbyteArray scanRecord)
86{
87 if (Q_UNLIKELY(qtObject == 0))
88 return;
89
90 reinterpret_cast<AndroidBroadcastReceiver*>(qtObject)->onReceiveLeScan(
91 env, bluetoothDevice.object(), rssi,
92 scanRecord);
93}
94Q_DECLARE_JNI_NATIVE_METHOD(QtBluetoothLE_leScanResult, leScanResult)
95
96static const char logTag[] = "QtBluetooth";
97static const char classErrorMsg[] = "Can't find class \"%s\"";
98
99#define FIND_AND_CHECK_CLASS(CLASS_NAME) clazz
100 = env.findClass<CLASS_NAME>(); if
101 (!clazz) {
102 __android_log_print(ANDROID_LOG_FATAL, logTag, classErrorMsg,
103 QtJniTypes::Traits<CLASS_NAME>::className().data());
104 return JNI_FALSE; \
105}
106
107#define LEHUB_SCOPED_METHOD(Method) Q_JNI_NATIVE_SCOPED_METHOD(Method, LowEnergyNotificationHub)
108
109static bool registerNatives()
110{
111 jclass clazz;
112 QJniEnvironment env;
113
114 FIND_AND_CHECK_CLASS(QtJniTypes::QtBtBroadcastReceiver);
115 if (!env.registerNativeMethods(clazz,
116 {
117 Q_JNI_NATIVE_METHOD(QtBroadcastReceiver_jniOnReceive)
118 }))
119 {
120 __android_log_print(ANDROID_LOG_FATAL, logTag,
121 "registerNativeMethods for BroadcastReceiver failed");
122 return false;
123 }
124
125 FIND_AND_CHECK_CLASS(QtJniTypes::QtBtLECentral);
126 if (!env.registerNativeMethods(clazz,
127 {
128 Q_JNI_NATIVE_METHOD(QtBluetoothLE_leScanResult),
129 LEHUB_SCOPED_METHOD(lowEnergy_connectionChange),
130 LEHUB_SCOPED_METHOD(lowEnergy_mtuChanged),
131 LEHUB_SCOPED_METHOD(lowEnergy_servicesDiscovered),
132 LEHUB_SCOPED_METHOD(lowEnergy_serviceDetailsDiscovered),
133 LEHUB_SCOPED_METHOD(lowEnergy_characteristicRead),
134 LEHUB_SCOPED_METHOD(lowEnergy_descriptorRead),
135 LEHUB_SCOPED_METHOD(lowEnergy_characteristicWritten),
136 LEHUB_SCOPED_METHOD(lowEnergy_descriptorWritten),
137 LEHUB_SCOPED_METHOD(lowEnergy_characteristicChanged),
138 LEHUB_SCOPED_METHOD(lowEnergy_serviceError),
139 LEHUB_SCOPED_METHOD(lowEnergy_remoteRssiRead)
140 }))
141 {
142 __android_log_print(ANDROID_LOG_FATAL, logTag,
143 "registerNativeMethods for QBLuetoothLE failed");
144 return false;
145 }
146
147 FIND_AND_CHECK_CLASS(QtJniTypes::QtBtLEServer);
148 if (!env.registerNativeMethods(clazz,
149 {
150 LEHUB_SCOPED_METHOD(lowEnergy_connectionChange),
151 LEHUB_SCOPED_METHOD(lowEnergy_mtuChanged),
152 LEHUB_SCOPED_METHOD(lowEnergy_advertisementError),
153 LEHUB_SCOPED_METHOD(lowEnergy_serverCharacteristicChanged),
154 LEHUB_SCOPED_METHOD(lowEnergy_serverDescriptorWritten)
155 }))
156 {
157 __android_log_print(ANDROID_LOG_FATAL, logTag,
158 "registerNativeMethods for QBLuetoothLEServer failed");
159 return false;
160 }
161
162 FIND_AND_CHECK_CLASS(QtJniTypes::QtBtSocketServer);
163 if (!env.registerNativeMethods(clazz,
164 {
165 Q_JNI_NATIVE_METHOD(QtBluetoothSocketServer_errorOccurred),
166 Q_JNI_NATIVE_METHOD(QtBluetoothSocketServer_newSocket)
167 }))
168 {
169 __android_log_print(ANDROID_LOG_FATAL, logTag,
170 "registerNativeMethods for SocketServer failed");
171 return false;
172 }
173
174 FIND_AND_CHECK_CLASS(QtJniTypes::QtBtInputStreamThread);
175 if (!env.registerNativeMethods(clazz,
176 {
177 Q_JNI_NATIVE_METHOD(QtBluetoothInputStreamThread_errorOccurred),
178 Q_JNI_NATIVE_METHOD(QtBluetoothInputStreamThread_readyData)
179 }))
180 {
181 __android_log_print(ANDROID_LOG_FATAL, logTag,
182 "registerNativeMethods for InputStreamThread failed");
183 return false;
184 }
185
186 return true;
187}
188
189QT_END_NAMESPACE
190
191Q_BLUETOOTH_EXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
192{
193 static bool initialized = false;
194 if (initialized)
195 return JNI_VERSION_1_6;
196 initialized = true;
197
198 typedef union {
199 JNIEnv *nativeEnvironment;
200 void *venv;
201 } UnionJNIEnvToVoid;
202
203 UnionJNIEnvToVoid uenv;
204 uenv.venv = 0;
205
206 if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_6) != JNI_OK) {
207 __android_log_print(ANDROID_LOG_FATAL, logTag, "GetEnv failed");
208 return -1;
209 }
210
211 const auto context = QNativeInterface::QAndroidApplication::context();
212 QtJniTypes::QtBtBroadcastReceiver::callStaticMethod<void>("setContext", context);
213
214 if (!registerNatives()) {
215 __android_log_print(ANDROID_LOG_FATAL, logTag, "registerNatives failed");
216 return -1;
217 }
218
219 if (QT_BT_ANDROID().isDebugEnabled())
220 __android_log_print(ANDROID_LOG_INFO, logTag, "Bluetooth start");
221
222 return JNI_VERSION_1_6;
223}
QT_BEGIN_NAMESPACE void QtBroadcastReceiver_jniOnReceive(JNIEnv *, jobject, jlong, QtJniTypes::Context, QtJniTypes::Intent)
#define FIND_AND_CHECK_CLASS(CLASS_NAME)
friend void QtBluetoothLE_leScanResult(JNIEnv *, jobject, jlong, QtJniTypes::BluetoothDevice, jint, jbyteArray)
void javaThreadErrorOccurred(int errorCode)
void javaThreadErrorOccurred(int errorCode)
#define LEHUB_SCOPED_METHOD(Method)
static const char classErrorMsg[]
static const char logTag[]
static void QtBluetoothInputStreamThread_errorOccurred(JNIEnv *, jobject, jlong qtObject, jint errorCode)
static void QtBluetoothInputStreamThread_readyData(JNIEnv *, jobject, jlong qtObject, jbyteArray buffer, jint bufferLength)
static void QtBluetoothSocketServer_newSocket(JNIEnv *, jobject, jlong qtObject, QtJniTypes::BluetoothSocket socket)
static void QtBluetoothSocketServer_errorOccurred(JNIEnv *, jobject, jlong qtObject, jint errorCode)
static bool registerNatives()
QString valueFromStaticFieldCache(const char *key, const char *className, const char *fieldName)