21 #include "../../SDL_internal.h"
35 #include "keyinfotable.h"
37 #include "../../events/SDL_events_c.h"
38 #include "../../video/android/SDL_androidkeyboard.h"
39 #include "../../video/android/SDL_androidmouse.h"
40 #include "../../video/android/SDL_androidtouch.h"
41 #include "../../video/android/SDL_androidvideo.h"
42 #include "../../video/android/SDL_androidwindow.h"
43 #include "../../joystick/android/SDL_sysjoystick_c.h"
44 #include "../../haptic/android/SDL_syshaptic_c.h"
46 #include <android/log.h>
47 #include <sys/system_properties.h>
49 #include <sys/types.h>
53 #define SDL_JAVA_PREFIX org_libsdl_app
54 #define CONCAT1(prefix, class, function) CONCAT2(prefix, class, function)
55 #define CONCAT2(prefix, class, function) Java_ ## prefix ## _ ## class ## _ ## function
56 #define SDL_JAVA_INTERFACE(function) CONCAT1(SDL_JAVA_PREFIX, SDLActivity, function)
57 #define SDL_JAVA_AUDIO_INTERFACE(function) CONCAT1(SDL_JAVA_PREFIX, SDLAudioManager, function)
58 #define SDL_JAVA_CONTROLLER_INTERFACE(function) CONCAT1(SDL_JAVA_PREFIX, SDLControllerManager, function)
59 #define SDL_JAVA_INTERFACE_INPUT_CONNECTION(function) CONCAT1(SDL_JAVA_PREFIX, SDLInputConnection, function)
62 #define ENCODING_PCM_8BIT 3
63 #define ENCODING_PCM_16BIT 2
64 #define ENCODING_PCM_FLOAT 4
67 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(
68 JNIEnv *env, jclass cls);
70 JNIEXPORT
int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(
71 JNIEnv *env, jclass cls,
72 jstring library, jstring
function, jobject
array);
74 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeDropFile)(
75 JNIEnv *env, jclass jcls,
78 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeSetScreenResolution)(
79 JNIEnv *env, jclass jcls,
80 jint surfaceWidth, jint surfaceHeight,
81 jint deviceWidth, jint deviceHeight, jint
format, jfloat rate);
83 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeResize)(
84 JNIEnv *env, jclass cls);
86 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceCreated)(
87 JNIEnv *env, jclass jcls);
89 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceChanged)(
90 JNIEnv *env, jclass jcls);
92 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed)(
93 JNIEnv *env, jclass jcls);
95 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeKeyDown)(
96 JNIEnv *env, jclass jcls,
99 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeKeyUp)(
100 JNIEnv *env, jclass jcls,
103 JNIEXPORT jboolean JNICALL SDL_JAVA_INTERFACE(onNativeSoftReturnKey)(
104 JNIEnv *env, jclass jcls);
106 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeKeyboardFocusLost)(
107 JNIEnv *env, jclass jcls);
109 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeTouch)(
110 JNIEnv *env, jclass jcls,
111 jint touch_device_id_in, jint pointer_finger_id_in,
112 jint
action, jfloat
x, jfloat
y, jfloat
p);
114 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeMouse)(
115 JNIEnv *env, jclass jcls,
118 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeAccel)(
119 JNIEnv *env, jclass jcls,
120 jfloat
x, jfloat
y, jfloat
z);
122 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeClipboardChanged)(
123 JNIEnv *env, jclass jcls);
125 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeLowMemory)(
126 JNIEnv *env, jclass cls);
128 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeSendQuit)(
129 JNIEnv *env, jclass cls);
131 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeQuit)(
132 JNIEnv *env, jclass cls);
134 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativePause)(
135 JNIEnv *env, jclass cls);
137 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeResume)(
138 JNIEnv *env, jclass cls);
140 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeFocusChanged)(
141 JNIEnv *env, jclass cls, jboolean hasFocus);
143 JNIEXPORT jstring JNICALL SDL_JAVA_INTERFACE(nativeGetHint)(
144 JNIEnv *env, jclass cls,
147 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeSetenv)(
148 JNIEnv *env, jclass cls,
151 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeOrientationChanged)(
152 JNIEnv *env, jclass cls,
155 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeAddTouch)(
156 JNIEnv* env, jclass cls,
157 jint touchId, jstring
name);
159 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativePermissionResult)(
160 JNIEnv* env, jclass cls,
161 jint requestCode, jboolean
result);
163 static JNINativeMethod SDLActivity_tab[] = {
164 {
"nativeSetupJNI",
"()I", SDL_JAVA_INTERFACE(nativeSetupJNI) },
165 {
"nativeRunMain",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)I", SDL_JAVA_INTERFACE(nativeRunMain) },
166 {
"onNativeDropFile",
"(Ljava/lang/String;)V", SDL_JAVA_INTERFACE(onNativeDropFile) },
167 {
"nativeSetScreenResolution",
"(IIIIIF)V", SDL_JAVA_INTERFACE(nativeSetScreenResolution) },
168 {
"onNativeResize",
"()V", SDL_JAVA_INTERFACE(onNativeResize) },
169 {
"onNativeSurfaceCreated",
"()V", SDL_JAVA_INTERFACE(onNativeSurfaceCreated) },
170 {
"onNativeSurfaceChanged",
"()V", SDL_JAVA_INTERFACE(onNativeSurfaceChanged) },
171 {
"onNativeSurfaceDestroyed",
"()V", SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed) },
172 {
"onNativeKeyDown",
"(I)V", SDL_JAVA_INTERFACE(onNativeKeyDown) },
173 {
"onNativeKeyUp",
"(I)V", SDL_JAVA_INTERFACE(onNativeKeyUp) },
174 {
"onNativeSoftReturnKey",
"()Z", SDL_JAVA_INTERFACE(onNativeSoftReturnKey) },
175 {
"onNativeKeyboardFocusLost",
"()V", SDL_JAVA_INTERFACE(onNativeKeyboardFocusLost) },
176 {
"onNativeTouch",
"(IIIFFF)V", SDL_JAVA_INTERFACE(onNativeTouch) },
177 {
"onNativeMouse",
"(IIFFZ)V", SDL_JAVA_INTERFACE(onNativeMouse) },
178 {
"onNativeAccel",
"(FFF)V", SDL_JAVA_INTERFACE(onNativeAccel) },
179 {
"onNativeClipboardChanged",
"()V", SDL_JAVA_INTERFACE(onNativeClipboardChanged) },
180 {
"nativeLowMemory",
"()V", SDL_JAVA_INTERFACE(nativeLowMemory) },
181 {
"nativeSendQuit",
"()V", SDL_JAVA_INTERFACE(nativeSendQuit) },
182 {
"nativeQuit",
"()V", SDL_JAVA_INTERFACE(nativeQuit) },
183 {
"nativePause",
"()V", SDL_JAVA_INTERFACE(nativePause) },
184 {
"nativeResume",
"()V", SDL_JAVA_INTERFACE(nativeResume) },
185 {
"nativeFocusChanged",
"(Z)V", SDL_JAVA_INTERFACE(nativeFocusChanged) },
186 {
"nativeGetHint",
"(Ljava/lang/String;)Ljava/lang/String;", SDL_JAVA_INTERFACE(nativeGetHint) },
187 {
"nativeSetenv",
"(Ljava/lang/String;Ljava/lang/String;)V", SDL_JAVA_INTERFACE(nativeSetenv) },
188 {
"onNativeOrientationChanged",
"(I)V", SDL_JAVA_INTERFACE(onNativeOrientationChanged) },
189 {
"nativeAddTouch",
"(ILjava/lang/String;)V", SDL_JAVA_INTERFACE(nativeAddTouch) },
190 {
"nativePermissionResult",
"(IZ)V", SDL_JAVA_INTERFACE(nativePermissionResult) }
194 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeCommitText)(
195 JNIEnv *env, jclass cls,
196 jstring
text, jint newCursorPosition);
198 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeGenerateScancodeForUnichar)(
199 JNIEnv *env, jclass cls,
202 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeSetComposingText)(
203 JNIEnv *env, jclass cls,
204 jstring
text, jint newCursorPosition);
206 static JNINativeMethod SDLInputConnection_tab[] = {
207 {
"nativeCommitText",
"(Ljava/lang/String;I)V", SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeCommitText) },
208 {
"nativeGenerateScancodeForUnichar",
"(C)V", SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeGenerateScancodeForUnichar) },
209 {
"nativeSetComposingText",
"(Ljava/lang/String;I)V", SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeSetComposingText) }
213 JNIEXPORT
void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(
214 JNIEnv *env, jclass jcls);
216 static JNINativeMethod SDLAudioManager_tab[] = {
217 {
"nativeSetupJNI",
"()I", SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI) }
221 JNIEXPORT
void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(
222 JNIEnv *env, jclass jcls);
224 JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativePadDown)(
225 JNIEnv *env, jclass jcls,
226 jint device_id, jint keycode);
228 JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativePadUp)(
229 JNIEnv *env, jclass jcls,
230 jint device_id, jint keycode);
232 JNIEXPORT
void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeJoy)(
233 JNIEnv *env, jclass jcls,
234 jint device_id, jint
axis, jfloat
value);
236 JNIEXPORT
void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat)(
237 JNIEnv *env, jclass jcls,
238 jint device_id, jint hat_id, jint
x, jint
y);
240 JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
241 JNIEnv *env, jclass jcls,
242 jint device_id, jstring device_name, jstring device_desc, jint vendor_id, jint product_id,
243 jboolean is_accelerometer, jint button_mask, jint naxes, jint nhats, jint nballs);
245 JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick)(
246 JNIEnv *env, jclass jcls,
249 JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddHaptic)(
250 JNIEnv *env, jclass jcls,
251 jint device_id, jstring device_name);
253 JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveHaptic)(
254 JNIEnv *env, jclass jcls,
257 static JNINativeMethod SDLControllerManager_tab[] = {
258 {
"nativeSetupJNI",
"()I", SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI) },
259 {
"onNativePadDown",
"(II)I", SDL_JAVA_CONTROLLER_INTERFACE(onNativePadDown) },
260 {
"onNativePadUp",
"(II)I", SDL_JAVA_CONTROLLER_INTERFACE(onNativePadUp) },
261 {
"onNativeJoy",
"(IIF)V", SDL_JAVA_CONTROLLER_INTERFACE(onNativeJoy) },
262 {
"onNativeHat",
"(IIII)V", SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat) },
263 {
"nativeAddJoystick",
"(ILjava/lang/String;Ljava/lang/String;IIZIIII)I", SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick) },
264 {
"nativeRemoveJoystick",
"(I)I", SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick) },
265 {
"nativeAddHaptic",
"(ILjava/lang/String;)I", SDL_JAVA_CONTROLLER_INTERFACE(nativeAddHaptic) },
266 {
"nativeRemoveHaptic",
"(I)I", SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveHaptic) }
273 static void checkJNIReady(
void);
284 static pthread_key_t mThreadKey;
285 static pthread_once_t key_once = PTHREAD_ONCE_INIT;
286 static JavaVM *mJavaVM =
NULL;
289 static jclass mActivityClass;
292 static jmethodID midClipboardGetText;
293 static jmethodID midClipboardHasText;
294 static jmethodID midClipboardSetText;
295 static jmethodID midCreateCustomCursor;
296 static jmethodID midGetContext;
297 static jmethodID midGetDisplayDPI;
298 static jmethodID midGetManifestEnvironmentVariables;
299 static jmethodID midGetNativeSurface;
300 static jmethodID midInitTouch;
301 static jmethodID midIsAndroidTV;
302 static jmethodID midIsChromebook;
303 static jmethodID midIsDeXMode;
304 static jmethodID midIsScreenKeyboardShown;
305 static jmethodID midIsTablet;
306 static jmethodID midManualBackButton;
307 static jmethodID midMinimizeWindow;
308 static jmethodID midOpenAPKExpansionInputStream;
309 static jmethodID midRequestPermission;
310 static jmethodID midSendMessage;
311 static jmethodID midSetActivityTitle;
312 static jmethodID midSetCustomCursor;
313 static jmethodID midSetOrientation;
314 static jmethodID midSetRelativeMouseEnabled;
315 static jmethodID midSetSurfaceViewFormat;
316 static jmethodID midSetSystemCursor;
317 static jmethodID midSetWindowStyle;
318 static jmethodID midShouldMinimizeOnFocusLoss;
319 static jmethodID midShowTextInput;
320 static jmethodID midSupportsRelativeMouse;
323 static jclass mAudioManagerClass;
326 static jmethodID midAudioOpen;
327 static jmethodID midAudioWriteByteBuffer;
328 static jmethodID midAudioWriteShortBuffer;
329 static jmethodID midAudioWriteFloatBuffer;
330 static jmethodID midAudioClose;
331 static jmethodID midCaptureOpen;
332 static jmethodID midCaptureReadByteBuffer;
333 static jmethodID midCaptureReadShortBuffer;
334 static jmethodID midCaptureReadFloatBuffer;
335 static jmethodID midCaptureClose;
336 static jmethodID midAudioSetThreadPriority;
339 static jclass mControllerManagerClass;
342 static jmethodID midPollInputDevices;
343 static jmethodID midPollHapticDevices;
344 static jmethodID midHapticRun;
345 static jmethodID midHapticStop;
349 static float fLastAccelerometer[3];
352 static SDL_bool bHasEnvironmentVariables;
355 static SDL_bool bPermissionRequestResult;
385 Android_JNI_SetEnv(JNIEnv *env) {
386 int status = pthread_setspecific(mThreadKey, env);
388 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"Failed pthread_setspecific() in Android_JNI_SetEnv() (err=%d)", status);
397 JNIEnv *env = pthread_getspecific(mThreadKey);
403 if (mJavaVM ==
NULL) {
404 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"Failed, there is no JavaVM");
410 status = (*mJavaVM)->AttachCurrentThread(mJavaVM, &env,
NULL);
412 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"Failed to attach current thread (err=%d)", status);
417 if (Android_JNI_SetEnv(env) < 0) {
432 if (mJavaVM ==
NULL) {
433 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"Failed, there is no JavaVM");
439 status = (*mJavaVM)->AttachCurrentThread(mJavaVM, &env,
NULL);
441 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"Failed to attach current thread (err=%d)", status);
446 if (Android_JNI_SetEnv(env) < 0) {
455 Android_JNI_ThreadDestroyed(
void *
value)
458 JNIEnv *env = (JNIEnv *)
value;
460 (*mJavaVM)->DetachCurrentThread(mJavaVM);
461 Android_JNI_SetEnv(
NULL);
467 Android_JNI_CreateKey(
void)
469 int status = pthread_key_create(&mThreadKey, Android_JNI_ThreadDestroyed);
471 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"Error initializing mThreadKey with pthread_key_create() (err=%d)", status);
476 Android_JNI_CreateKey_once(
void)
478 int status = pthread_once(&key_once, Android_JNI_CreateKey);
480 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"Error initializing mThreadKey with pthread_once() (err=%d)", status);
485 register_methods(JNIEnv *env,
const char *classname, JNINativeMethod *methods,
int nb)
487 jclass clazz = (*env)->FindClass(env, classname);
488 if (clazz ==
NULL || (*env)->RegisterNatives(env, clazz, methods, nb) < 0) {
489 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"Failed to register methods of %s", classname);
495 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm,
void *reserved)
500 if ((*mJavaVM)->GetEnv(mJavaVM, (
void **)&env, JNI_VERSION_1_4) != JNI_OK) {
501 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"Failed to get JNI Env");
502 return JNI_VERSION_1_4;
505 register_methods(env,
"org/libsdl/app/SDLActivity", SDLActivity_tab,
SDL_arraysize(SDLActivity_tab));
506 register_methods(env,
"org/libsdl/app/SDLInputConnection", SDLInputConnection_tab,
SDL_arraysize(SDLInputConnection_tab));
507 register_methods(env,
"org/libsdl/app/SDLAudioManager", SDLAudioManager_tab,
SDL_arraysize(SDLAudioManager_tab));
508 register_methods(env,
"org/libsdl/app/SDLControllerManager", SDLControllerManager_tab,
SDL_arraysize(SDLControllerManager_tab));
510 return JNI_VERSION_1_4;
513 void checkJNIReady(
void)
515 if (!mActivityClass || !mAudioManagerClass || !mControllerManagerClass) {
524 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cls)
526 __android_log_print(ANDROID_LOG_VERBOSE,
"SDL",
"nativeSetupJNI()");
532 Android_JNI_CreateKey_once();
535 Android_JNI_SetEnv(env);
537 if (mJavaVM ==
NULL) {
538 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"failed to found a JavaVM");
549 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"failed to create Android_ActivityMutex mutex");
555 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"failed to create Android_PauseSem semaphore");
560 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"failed to create Android_ResumeSem semaphore");
563 mActivityClass = (jclass)((*env)->NewGlobalRef(env, cls));
565 midClipboardGetText = (*env)->GetStaticMethodID(env, mActivityClass,
"clipboardGetText",
"()Ljava/lang/String;");
566 midClipboardHasText = (*env)->GetStaticMethodID(env, mActivityClass,
"clipboardHasText",
"()Z");
567 midClipboardSetText = (*env)->GetStaticMethodID(env, mActivityClass,
"clipboardSetText",
"(Ljava/lang/String;)V");
568 midCreateCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass,
"createCustomCursor",
"([IIIII)I");
569 midGetContext = (*env)->GetStaticMethodID(env, mActivityClass,
"getContext",
"()Landroid/content/Context;");
570 midGetDisplayDPI = (*env)->GetStaticMethodID(env, mActivityClass,
"getDisplayDPI",
"()Landroid/util/DisplayMetrics;");
571 midGetManifestEnvironmentVariables = (*env)->GetStaticMethodID(env, mActivityClass,
"getManifestEnvironmentVariables",
"()Z");
572 midGetNativeSurface = (*env)->GetStaticMethodID(env, mActivityClass,
"getNativeSurface",
"()Landroid/view/Surface;");
573 midInitTouch = (*env)->GetStaticMethodID(env, mActivityClass,
"initTouch",
"()V");
574 midIsAndroidTV = (*env)->GetStaticMethodID(env, mActivityClass,
"isAndroidTV",
"()Z");
575 midIsChromebook = (*env)->GetStaticMethodID(env, mActivityClass,
"isChromebook",
"()Z");
576 midIsDeXMode = (*env)->GetStaticMethodID(env, mActivityClass,
"isDeXMode",
"()Z");
577 midIsScreenKeyboardShown = (*env)->GetStaticMethodID(env, mActivityClass,
"isScreenKeyboardShown",
"()Z");
578 midIsTablet = (*env)->GetStaticMethodID(env, mActivityClass,
"isTablet",
"()Z");
579 midManualBackButton = (*env)->GetStaticMethodID(env, mActivityClass,
"manualBackButton",
"()V");
580 midMinimizeWindow = (*env)->GetStaticMethodID(env, mActivityClass,
"minimizeWindow",
"()V");
581 midOpenAPKExpansionInputStream = (*env)->GetStaticMethodID(env, mActivityClass,
"openAPKExpansionInputStream",
"(Ljava/lang/String;)Ljava/io/InputStream;");
582 midRequestPermission = (*env)->GetStaticMethodID(env, mActivityClass,
"requestPermission",
"(Ljava/lang/String;I)V");
583 midSendMessage = (*env)->GetStaticMethodID(env, mActivityClass,
"sendMessage",
"(II)Z");
584 midSetActivityTitle = (*env)->GetStaticMethodID(env, mActivityClass,
"setActivityTitle",
"(Ljava/lang/String;)Z");
585 midSetCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass,
"setCustomCursor",
"(I)Z");
586 midSetOrientation = (*env)->GetStaticMethodID(env, mActivityClass,
"setOrientation",
"(IIZLjava/lang/String;)V");
587 midSetRelativeMouseEnabled = (*env)->GetStaticMethodID(env, mActivityClass,
"setRelativeMouseEnabled",
"(Z)Z");
588 midSetSurfaceViewFormat = (*env)->GetStaticMethodID(env, mActivityClass,
"setSurfaceViewFormat",
"(I)V");
589 midSetSystemCursor = (*env)->GetStaticMethodID(env, mActivityClass,
"setSystemCursor",
"(I)Z");
590 midSetWindowStyle = (*env)->GetStaticMethodID(env, mActivityClass,
"setWindowStyle",
"(Z)V");
591 midShouldMinimizeOnFocusLoss = (*env)->GetStaticMethodID(env, mActivityClass,
"shouldMinimizeOnFocusLoss",
"()Z");
592 midShowTextInput = (*env)->GetStaticMethodID(env, mActivityClass,
"showTextInput",
"(IIII)Z");
593 midSupportsRelativeMouse = (*env)->GetStaticMethodID(env, mActivityClass,
"supportsRelativeMouse",
"()Z");
595 if (!midClipboardGetText ||
596 !midClipboardHasText ||
597 !midClipboardSetText ||
598 !midCreateCustomCursor ||
601 !midGetManifestEnvironmentVariables ||
602 !midGetNativeSurface ||
607 !midIsScreenKeyboardShown ||
609 !midManualBackButton ||
610 !midMinimizeWindow ||
611 !midOpenAPKExpansionInputStream ||
612 !midRequestPermission ||
614 !midSetActivityTitle ||
615 !midSetCustomCursor ||
616 !midSetOrientation ||
617 !midSetRelativeMouseEnabled ||
618 !midSetSurfaceViewFormat ||
619 !midSetSystemCursor ||
620 !midSetWindowStyle ||
621 !midShouldMinimizeOnFocusLoss ||
623 !midSupportsRelativeMouse) {
624 __android_log_print(ANDROID_LOG_WARN,
"SDL",
"Missing some Java callbacks, do you have the latest version of SDLActivity.java?");
631 JNIEXPORT
void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cls)
633 __android_log_print(ANDROID_LOG_VERBOSE,
"SDL",
"AUDIO nativeSetupJNI()");
635 mAudioManagerClass = (jclass)((*env)->NewGlobalRef(env, cls));
637 midAudioOpen = (*env)->GetStaticMethodID(env, mAudioManagerClass,
638 "audioOpen",
"(IIII)[I");
639 midAudioWriteByteBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
640 "audioWriteByteBuffer",
"([B)V");
641 midAudioWriteShortBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
642 "audioWriteShortBuffer",
"([S)V");
643 midAudioWriteFloatBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
644 "audioWriteFloatBuffer",
"([F)V");
645 midAudioClose = (*env)->GetStaticMethodID(env, mAudioManagerClass,
646 "audioClose",
"()V");
647 midCaptureOpen = (*env)->GetStaticMethodID(env, mAudioManagerClass,
648 "captureOpen",
"(IIII)[I");
649 midCaptureReadByteBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
650 "captureReadByteBuffer",
"([BZ)I");
651 midCaptureReadShortBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
652 "captureReadShortBuffer",
"([SZ)I");
653 midCaptureReadFloatBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
654 "captureReadFloatBuffer",
"([FZ)I");
655 midCaptureClose = (*env)->GetStaticMethodID(env, mAudioManagerClass,
656 "captureClose",
"()V");
657 midAudioSetThreadPriority = (*env)->GetStaticMethodID(env, mAudioManagerClass,
658 "audioSetThreadPriority",
"(ZI)V");
660 if (!midAudioOpen || !midAudioWriteByteBuffer || !midAudioWriteShortBuffer || !midAudioWriteFloatBuffer || !midAudioClose ||
661 !midCaptureOpen || !midCaptureReadByteBuffer || !midCaptureReadShortBuffer || !midCaptureReadFloatBuffer || !midCaptureClose || !midAudioSetThreadPriority) {
662 __android_log_print(ANDROID_LOG_WARN,
"SDL",
"Missing some Java callbacks, do you have the latest version of SDLAudioManager.java?");
669 JNIEXPORT
void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cls)
671 __android_log_print(ANDROID_LOG_VERBOSE,
"SDL",
"CONTROLLER nativeSetupJNI()");
673 mControllerManagerClass = (jclass)((*env)->NewGlobalRef(env, cls));
675 midPollInputDevices = (*env)->GetStaticMethodID(env, mControllerManagerClass,
676 "pollInputDevices",
"()V");
677 midPollHapticDevices = (*env)->GetStaticMethodID(env, mControllerManagerClass,
678 "pollHapticDevices",
"()V");
679 midHapticRun = (*env)->GetStaticMethodID(env, mControllerManagerClass,
680 "hapticRun",
"(IFI)V");
681 midHapticStop = (*env)->GetStaticMethodID(env, mControllerManagerClass,
682 "hapticStop",
"(I)V");
684 if (!midPollInputDevices || !midPollHapticDevices || !midHapticRun || !midHapticStop) {
685 __android_log_print(ANDROID_LOG_WARN,
"SDL",
"Missing some Java callbacks, do you have the latest version of SDLControllerManager.java?");
695 JNIEXPORT
int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(JNIEnv *env, jclass cls, jstring library, jstring
function, jobject
array)
698 const char *library_file;
699 void *library_handle;
701 __android_log_print(ANDROID_LOG_VERBOSE,
"SDL",
"nativeRunMain()");
704 Android_JNI_SetEnv(env);
706 library_file = (*env)->GetStringUTFChars(env, library,
NULL);
707 library_handle = dlopen(library_file, RTLD_GLOBAL);
709 if (!library_handle) {
712 const char *library_name =
SDL_strrchr(library_file,
'/');
713 if (library_name && *library_name) {
715 library_handle = dlopen(library_name, RTLD_GLOBAL);
719 if (library_handle) {
720 const char *function_name;
723 function_name = (*env)->GetStringUTFChars(env,
function,
NULL);
733 len = (*env)->GetArrayLength(env,
array);
740 for (
i = 0;
i <
len; ++
i) {
743 jstring
string = (*env)->GetObjectArrayElement(env,
array,
i);
745 utf = (*env)->GetStringUTFChars(env,
string, 0);
748 (*env)->ReleaseStringUTFChars(env,
string, utf);
750 (*env)->DeleteLocalRef(env,
string);
764 for (
i = 0;
i < argc; ++
i) {
770 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"nativeRunMain(): Couldn't find function %s in library %s", function_name, library_file);
772 (*env)->ReleaseStringUTFChars(env,
function, function_name);
774 dlclose(library_handle);
777 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"nativeRunMain(): Couldn't load library %s", library_file);
779 (*env)->ReleaseStringUTFChars(env, library, library_file);
783 Android_JNI_SetEnv(
NULL);
792 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeDropFile)(
793 JNIEnv *env, jclass jcls,
813 int pauseSignaled = 0;
814 int resumeSignaled = 0;
823 if (pauseSignaled > resumeSignaled) {
831 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeSetScreenResolution)(
832 JNIEnv *env, jclass jcls,
833 jint surfaceWidth, jint surfaceHeight,
834 jint deviceWidth, jint deviceHeight, jint
format, jfloat rate)
844 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeResize)(
845 JNIEnv *env, jclass jcls)
857 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeOrientationChanged)(
858 JNIEnv *env, jclass jcls,
874 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeAddTouch)(
875 JNIEnv* env, jclass cls,
876 jint touchId, jstring
name)
878 const char *utfname = (*env)->GetStringUTFChars(env,
name,
NULL);
882 (*env)->ReleaseStringUTFChars(env,
name, utfname);
885 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativePermissionResult)(
886 JNIEnv* env, jclass cls,
887 jint requestCode, jboolean
result)
889 bPermissionRequestResult =
result;
894 JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativePadDown)(
895 JNIEnv *env, jclass jcls,
896 jint device_id, jint keycode)
898 return Android_OnPadDown(device_id, keycode);
902 JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativePadUp)(
903 JNIEnv *env, jclass jcls,
904 jint device_id, jint keycode)
906 return Android_OnPadUp(device_id, keycode);
910 JNIEXPORT
void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeJoy)(
911 JNIEnv *env, jclass jcls,
918 JNIEXPORT
void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat)(
919 JNIEnv *env, jclass jcls,
920 jint device_id, jint hat_id, jint
x, jint
y)
922 Android_OnHat(device_id, hat_id,
x,
y);
926 JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
927 JNIEnv *env, jclass jcls,
928 jint device_id, jstring device_name, jstring device_desc,
929 jint vendor_id, jint product_id, jboolean is_accelerometer,
930 jint button_mask, jint naxes, jint nhats, jint nballs)
933 const char *
name = (*env)->GetStringUTFChars(env, device_name,
NULL);
934 const char *desc = (*env)->GetStringUTFChars(env, device_desc,
NULL);
936 retval = Android_AddJoystick(device_id,
name, desc, vendor_id, product_id, is_accelerometer ?
SDL_TRUE :
SDL_FALSE, button_mask, naxes, nhats, nballs);
938 (*env)->ReleaseStringUTFChars(env, device_name,
name);
939 (*env)->ReleaseStringUTFChars(env, device_desc, desc);
944 JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick)(
945 JNIEnv *env, jclass jcls,
948 return Android_RemoveJoystick(device_id);
951 JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddHaptic)(
952 JNIEnv *env, jclass jcls, jint device_id, jstring device_name)
955 const char *
name = (*env)->GetStringUTFChars(env, device_name,
NULL);
959 (*env)->ReleaseStringUTFChars(env, device_name,
name);
964 JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveHaptic)(
965 JNIEnv *env, jclass jcls, jint device_id)
967 return Android_RemoveHaptic(device_id);
971 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceCreated)(JNIEnv *env, jclass jcls)
981 SDL_SetError(
"Could not fetch native window from UI thread");
989 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceChanged)(JNIEnv *env, jclass jcls)
1010 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed)(JNIEnv *env, jclass jcls)
1012 int nb_attempt = 50;
1024 if (!
data->backup_done) {
1026 if (nb_attempt == 0) {
1027 SDL_SetError(
"Try to release egl_surface with context probably still active");
1036 SDL_EGL_DestroySurface(
_this,
data->egl_surface);
1040 if (
data->native_window) {
1041 ANativeWindow_release(
data->native_window);
1052 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeKeyDown)(
1053 JNIEnv *env, jclass jcls,
1060 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeKeyUp)(
1061 JNIEnv *env, jclass jcls,
1068 JNIEXPORT jboolean JNICALL SDL_JAVA_INTERFACE(onNativeSoftReturnKey)(
1069 JNIEnv *env, jclass jcls)
1079 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeKeyboardFocusLost)(
1080 JNIEnv *env, jclass jcls)
1088 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeTouch)(
1089 JNIEnv *env, jclass jcls,
1090 jint touch_device_id_in, jint pointer_finger_id_in,
1091 jint
action, jfloat
x, jfloat
y, jfloat
p)
1101 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeMouse)(
1102 JNIEnv *env, jclass jcls,
1113 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeAccel)(
1114 JNIEnv *env, jclass jcls,
1115 jfloat
x, jfloat
y, jfloat
z)
1117 fLastAccelerometer[0] =
x;
1118 fLastAccelerometer[1] =
y;
1119 fLastAccelerometer[2] =
z;
1124 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(onNativeClipboardChanged)(
1125 JNIEnv *env, jclass jcls)
1131 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeLowMemory)(
1132 JNIEnv *env, jclass cls)
1138 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeSendQuit)(
1139 JNIEnv *env, jclass cls)
1158 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeQuit)(
1159 JNIEnv *env, jclass cls)
1179 if (str && str[0]) {
1180 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"SDLActivity thread ends (error=%s)", str);
1182 __android_log_print(ANDROID_LOG_VERBOSE,
"SDL",
"SDLActivity thread ends");
1187 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativePause)(
1188 JNIEnv *env, jclass cls)
1190 __android_log_print(ANDROID_LOG_VERBOSE,
"SDL",
"nativePause()");
1198 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeResume)(
1199 JNIEnv *env, jclass cls)
1201 __android_log_print(ANDROID_LOG_VERBOSE,
"SDL",
"nativeResume()");
1210 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeFocusChanged)(
1211 JNIEnv *env, jclass cls, jboolean hasFocus)
1216 __android_log_print(ANDROID_LOG_VERBOSE,
"SDL",
"nativeFocusChanged()");
1223 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeCommitText)(
1224 JNIEnv *env, jclass cls,
1225 jstring
text, jint newCursorPosition)
1227 const char *utftext = (*env)->GetStringUTFChars(env,
text,
NULL);
1231 (*env)->ReleaseStringUTFChars(env,
text, utftext);
1234 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeGenerateScancodeForUnichar)(
1235 JNIEnv *env, jclass cls,
1242 if (chUnicode < 127) {
1263 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeSetComposingText)(
1264 JNIEnv *env, jclass cls,
1265 jstring
text, jint newCursorPosition)
1267 const char *utftext = (*env)->GetStringUTFChars(env,
text,
NULL);
1271 (*env)->ReleaseStringUTFChars(env,
text, utftext);
1274 JNIEXPORT jstring JNICALL SDL_JAVA_INTERFACE(nativeGetHint)(
1275 JNIEnv *env, jclass cls,
1278 const char *utfname = (*env)->GetStringUTFChars(env,
name,
NULL);
1281 jstring
result = (*env)->NewStringUTF(env, hint);
1282 (*env)->ReleaseStringUTFChars(env,
name, utfname);
1287 JNIEXPORT
void JNICALL SDL_JAVA_INTERFACE(nativeSetenv)(
1288 JNIEnv *env, jclass cls,
1291 const char *utfname = (*env)->GetStringUTFChars(env,
name,
NULL);
1292 const char *utfvalue = (*env)->GetStringUTFChars(env,
value,
NULL);
1296 (*env)->ReleaseStringUTFChars(env,
name, utfname);
1297 (*env)->ReleaseStringUTFChars(env,
value, utfvalue);
1306 struct LocalReferenceHolder
1312 static struct LocalReferenceHolder LocalReferenceHolder_Setup(const char *
func)
1314 struct LocalReferenceHolder refholder;
1315 refholder.m_env =
NULL;
1316 refholder.m_func =
func;
1323 static SDL_bool LocalReferenceHolder_Init(
struct LocalReferenceHolder *refholder, JNIEnv *env)
1325 const int capacity = 16;
1326 if ((*env)->PushLocalFrame(env, capacity) < 0) {
1327 SDL_SetError(
"Failed to allocate enough JVM local references");
1331 refholder->m_env = env;
1335 static void LocalReferenceHolder_Cleanup(
struct LocalReferenceHolder *refholder)
1338 SDL_Log(
"Leaving function %s", refholder->m_func);
1340 if (refholder->m_env) {
1341 JNIEnv *env = refholder->m_env;
1342 (*env)->PopLocalFrame(env,
NULL);
1349 ANativeWindow *anw =
NULL;
1353 s = (*env)->CallStaticObjectMethod(env, mActivityClass, midGetNativeSurface);
1355 anw = ANativeWindow_fromSurface(env,
s);
1356 (*env)->DeleteLocalRef(env,
s);
1370 if (
format == WINDOW_FORMAT_RGBA_8888) {
1372 }
else if (
format == WINDOW_FORMAT_RGBX_8888) {
1374 }
else if (
format == WINDOW_FORMAT_RGB_565) {
1379 (*env)->CallStaticVoidMethod(env, mActivityClass, midSetSurfaceViewFormat, new_format);
1386 jstring jtitle = (*env)->NewStringUTF(env, title);
1387 (*env)->CallStaticBooleanMethod(env, mActivityClass, midSetActivityTitle, jtitle);
1388 (*env)->DeleteLocalRef(env, jtitle);
1394 (*env)->CallStaticVoidMethod(env, mActivityClass, midSetWindowStyle, fullscreen ? 1 : 0);
1401 jstring jhint = (*env)->NewStringUTF(env, (hint ? hint :
""));
1402 (*env)->CallStaticVoidMethod(env, mActivityClass, midSetOrientation,
w,
h, (resizable? 1 : 0), jhint);
1403 (*env)->DeleteLocalRef(env, jhint);
1409 (*env)->CallStaticVoidMethod(env, mActivityClass, midMinimizeWindow);
1415 return (*env)->CallStaticBooleanMethod(env, mActivityClass, midShouldMinimizeOnFocusLoss);
1424 for (
i = 0;
i < 3; ++
i) {
1437 static int audioBufferFormat = 0;
1438 static jobject audioBuffer =
NULL;
1439 static void *audioBufferPinned =
NULL;
1440 static int captureBufferFormat = 0;
1441 static jobject captureBuffer =
NULL;
1446 jobject jbufobj =
NULL;
1448 int *resultElements;
1455 audioformat = ENCODING_PCM_8BIT;
1458 audioformat = ENCODING_PCM_16BIT;
1461 audioformat = ENCODING_PCM_FLOAT;
1468 __android_log_print(ANDROID_LOG_VERBOSE,
"SDL",
"SDL audio: opening device for capture");
1471 __android_log_print(ANDROID_LOG_VERBOSE,
"SDL",
"SDL audio: opening device for output");
1476 return SDL_SetError(
"Java-side initialization failed");
1479 if ((*env)->GetArrayLength(env, (jintArray)
result) != 4) {
1480 return SDL_SetError(
"Unexpected results from Java, expected 4, got %d", (*env)->GetArrayLength(env, (jintArray)
result));
1483 resultElements = (*env)->GetIntArrayElements(env, (jintArray)
result, &isCopy);
1485 audioformat = resultElements[1];
1486 switch (audioformat) {
1487 case ENCODING_PCM_8BIT:
1490 case ENCODING_PCM_16BIT:
1493 case ENCODING_PCM_FLOAT:
1497 return SDL_SetError(
"Unexpected audio format from Java: %d\n", audioformat);
1501 (*env)->ReleaseIntArrayElements(env, (jintArray)
result, resultElements, JNI_ABORT);
1502 (*env)->DeleteLocalRef(env,
result);
1506 switch (audioformat) {
1507 case ENCODING_PCM_8BIT:
1510 if (audioBufferLocal) {
1511 jbufobj = (*env)->NewGlobalRef(env, audioBufferLocal);
1512 (*env)->DeleteLocalRef(env, audioBufferLocal);
1516 case ENCODING_PCM_16BIT:
1519 if (audioBufferLocal) {
1520 jbufobj = (*env)->NewGlobalRef(env, audioBufferLocal);
1521 (*env)->DeleteLocalRef(env, audioBufferLocal);
1525 case ENCODING_PCM_FLOAT:
1528 if (audioBufferLocal) {
1529 jbufobj = (*env)->NewGlobalRef(env, audioBufferLocal);
1530 (*env)->DeleteLocalRef(env, audioBufferLocal);
1535 return SDL_SetError(
"Unexpected audio format from Java: %d\n", audioformat);
1538 if (jbufobj ==
NULL) {
1539 __android_log_print(ANDROID_LOG_WARN,
"SDL",
"SDL audio: could not allocate an audio buffer");
1544 captureBufferFormat = audioformat;
1545 captureBuffer = jbufobj;
1547 audioBufferFormat = audioformat;
1548 audioBuffer = jbufobj;
1554 switch (audioformat) {
1555 case ENCODING_PCM_8BIT:
1556 audioBufferPinned = (*env)->GetByteArrayElements(env, (jbyteArray)audioBuffer, &isCopy);
1558 case ENCODING_PCM_16BIT:
1559 audioBufferPinned = (*env)->GetShortArrayElements(env, (jshortArray)audioBuffer, &isCopy);
1561 case ENCODING_PCM_FLOAT:
1562 audioBufferPinned = (*env)->GetFloatArrayElements(env, (jfloatArray)audioBuffer, &isCopy);
1565 return SDL_SetError(
"Unexpected audio format from Java: %d\n", audioformat);
1573 return displayOrientation;
1580 jobject jDisplayObj = (*env)->CallStaticObjectMethod(env, mActivityClass, midGetDisplayDPI);
1581 jclass jDisplayClass = (*env)->GetObjectClass(env, jDisplayObj);
1583 jfieldID fidXdpi = (*env)->GetFieldID(env, jDisplayClass,
"xdpi",
"F");
1584 jfieldID fidYdpi = (*env)->GetFieldID(env, jDisplayClass,
"ydpi",
"F");
1585 jfieldID fidDdpi = (*env)->GetFieldID(env, jDisplayClass,
"densityDpi",
"I");
1587 float nativeXdpi = (*env)->GetFloatField(env, jDisplayObj, fidXdpi);
1588 float nativeYdpi = (*env)->GetFloatField(env, jDisplayObj, fidYdpi);
1589 int nativeDdpi = (*env)->GetIntField(env, jDisplayObj, fidDdpi);
1592 (*env)->DeleteLocalRef(env, jDisplayObj);
1593 (*env)->DeleteLocalRef(env, jDisplayClass);
1596 *ddpi = (float)nativeDdpi;
1610 return audioBufferPinned;
1617 switch (audioBufferFormat) {
1618 case ENCODING_PCM_8BIT:
1619 (*env)->ReleaseByteArrayElements(env, (jbyteArray)audioBuffer, (jbyte *)audioBufferPinned, JNI_COMMIT);
1620 (*env)->CallStaticVoidMethod(env, mAudioManagerClass, midAudioWriteByteBuffer, (jbyteArray)audioBuffer);
1622 case ENCODING_PCM_16BIT:
1623 (*env)->ReleaseShortArrayElements(env, (jshortArray)audioBuffer, (jshort *)audioBufferPinned, JNI_COMMIT);
1624 (*env)->CallStaticVoidMethod(env, mAudioManagerClass, midAudioWriteShortBuffer, (jshortArray)audioBuffer);
1626 case ENCODING_PCM_FLOAT:
1627 (*env)->ReleaseFloatArrayElements(env, (jfloatArray)audioBuffer, (jfloat *)audioBufferPinned, JNI_COMMIT);
1628 (*env)->CallStaticVoidMethod(env, mAudioManagerClass, midAudioWriteFloatBuffer, (jfloatArray)audioBuffer);
1631 __android_log_print(ANDROID_LOG_WARN,
"SDL",
"SDL audio: unhandled audio buffer format");
1641 jboolean isCopy = JNI_FALSE;
1644 switch (captureBufferFormat) {
1645 case ENCODING_PCM_8BIT:
1646 SDL_assert((*env)->GetArrayLength(env, (jshortArray)captureBuffer) == buflen);
1647 br = (*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_TRUE);
1649 jbyte *
ptr = (*env)->GetByteArrayElements(env, (jbyteArray)captureBuffer, &isCopy);
1651 (*env)->ReleaseByteArrayElements(env, (jbyteArray)captureBuffer,
ptr, JNI_ABORT);
1654 case ENCODING_PCM_16BIT:
1655 SDL_assert((*env)->GetArrayLength(env, (jshortArray)captureBuffer) == (buflen /
sizeof(
Sint16)));
1656 br = (*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_TRUE);
1658 jshort *
ptr = (*env)->GetShortArrayElements(env, (jshortArray)captureBuffer, &isCopy);
1661 (*env)->ReleaseShortArrayElements(env, (jshortArray)captureBuffer,
ptr, JNI_ABORT);
1664 case ENCODING_PCM_FLOAT:
1665 SDL_assert((*env)->GetArrayLength(env, (jfloatArray)captureBuffer) == (buflen /
sizeof(
float)));
1666 br = (*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureReadFloatBuffer, (jfloatArray)captureBuffer, JNI_TRUE);
1668 jfloat *
ptr = (*env)->GetFloatArrayElements(env, (jfloatArray)captureBuffer, &isCopy);
1669 br *=
sizeof(float);
1671 (*env)->ReleaseFloatArrayElements(env, (jfloatArray)captureBuffer,
ptr, JNI_ABORT);
1675 __android_log_print(ANDROID_LOG_WARN,
"SDL",
"SDL audio: unhandled capture buffer format");
1685 switch (captureBufferFormat) {
1686 case ENCODING_PCM_8BIT:
1688 const jint
len = (*env)->GetArrayLength(env, (jbyteArray)captureBuffer);
1689 while ((*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_FALSE) ==
len) { }
1692 case ENCODING_PCM_16BIT:
1694 const jint
len = (*env)->GetArrayLength(env, (jshortArray)captureBuffer);
1695 while ((*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_FALSE) ==
len) { }
1698 case ENCODING_PCM_FLOAT:
1700 const jint
len = (*env)->GetArrayLength(env, (jfloatArray)captureBuffer);
1701 while ((*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadFloatBuffer, (jfloatArray)captureBuffer, JNI_FALSE) ==
len) { }
1705 __android_log_print(ANDROID_LOG_WARN,
"SDL",
"SDL audio: flushing unhandled capture buffer format");
1709 switch (captureBufferFormat) {
1710 case ENCODING_PCM_8BIT:
1711 (*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_FALSE);
1713 case ENCODING_PCM_16BIT:
1714 (*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_FALSE);
1716 case ENCODING_PCM_FLOAT:
1717 (*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureReadFloatBuffer, (jfloatArray)captureBuffer, JNI_FALSE);
1720 __android_log_print(ANDROID_LOG_WARN,
"SDL",
"SDL audio: flushing unhandled capture buffer format");
1731 (*env)->CallStaticVoidMethod(env, mAudioManagerClass, midCaptureClose);
1732 if (captureBuffer) {
1733 (*env)->DeleteGlobalRef(env, captureBuffer);
1734 captureBuffer =
NULL;
1737 (*env)->CallStaticVoidMethod(env, mAudioManagerClass, midAudioClose);
1739 (*env)->DeleteGlobalRef(env, audioBuffer);
1741 audioBufferPinned =
NULL;
1749 (*env)->CallStaticVoidMethod(env, mAudioManagerClass, midAudioSetThreadPriority, iscapture, device_id);
1757 jthrowable exception;
1762 exception = (*env)->ExceptionOccurred(env);
1763 if (exception !=
NULL) {
1767 (*env)->ExceptionClear(env);
1770 jclass exceptionClass = (*env)->GetObjectClass(env, exception);
1771 jclass classClass = (*env)->FindClass(env,
"java/lang/Class");
1772 jstring exceptionName;
1773 const char *exceptionNameUTF8;
1774 jstring exceptionMessage;
1776 mid = (*env)->GetMethodID(env, classClass,
"getName",
"()Ljava/lang/String;");
1777 exceptionName = (jstring)(*env)->CallObjectMethod(env, exceptionClass, mid);
1778 exceptionNameUTF8 = (*env)->GetStringUTFChars(env, exceptionName, 0);
1780 mid = (*env)->GetMethodID(env, exceptionClass,
"getMessage",
"()Ljava/lang/String;");
1781 exceptionMessage = (jstring)(*env)->CallObjectMethod(env, exception, mid);
1783 if (exceptionMessage !=
NULL) {
1784 const char *exceptionMessageUTF8 = (*env)->GetStringUTFChars(env, exceptionMessage, 0);
1785 SDL_SetError(
"%s: %s", exceptionNameUTF8, exceptionMessageUTF8);
1786 (*env)->ReleaseStringUTFChars(env, exceptionMessage, exceptionMessageUTF8);
1791 (*env)->ReleaseStringUTFChars(env, exceptionName, exceptionNameUTF8);
1800 static int Internal_Android_JNI_FileOpen(
SDL_RWops *
ctx)
1802 struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
1808 jobject assetManager;
1809 jobject inputStream;
1811 jobject readableByteChannel;
1812 jstring fileNameJString;
1815 jfieldID descriptor;
1818 if (!LocalReferenceHolder_Init(&refs, env)) {
1822 fileNameJString = (jstring)
ctx->hidden.androidio.fileNameRef;
1823 ctx->hidden.androidio.position = 0;
1826 context = (*env)->CallStaticObjectMethod(env, mActivityClass, midGetContext);
1829 mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env,
context),
1830 "getAssets",
"()Landroid/content/res/AssetManager;");
1831 assetManager = (*env)->CallObjectMethod(env,
context, mid);
1836 mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, assetManager),
"openFd",
"(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;");
1837 inputStream = (*env)->CallObjectMethod(env, assetManager, mid, fileNameJString);
1838 if (Android_JNI_ExceptionOccurred(
SDL_TRUE)) {
1842 mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, inputStream),
"getStartOffset",
"()J");
1843 ctx->hidden.androidio.offset = (long)(*env)->CallLongMethod(env, inputStream, mid);
1844 if (Android_JNI_ExceptionOccurred(
SDL_TRUE)) {
1848 mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, inputStream),
"getDeclaredLength",
"()J");
1849 ctx->hidden.androidio.size = (long)(*env)->CallLongMethod(env, inputStream, mid);
1850 if (Android_JNI_ExceptionOccurred(
SDL_TRUE)) {
1854 mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, inputStream),
"getFileDescriptor",
"()Ljava/io/FileDescriptor;");
1855 fd = (*env)->CallObjectMethod(env, inputStream, mid);
1856 fdCls = (*env)->GetObjectClass(env,
fd);
1857 descriptor = (*env)->GetFieldID(env, fdCls,
"descriptor",
"I");
1858 ctx->hidden.androidio.fd = (*env)->GetIntField(env,
fd, descriptor);
1859 ctx->hidden.androidio.assetFileDescriptorRef = (*env)->NewGlobalRef(env, inputStream);
1862 lseek(
ctx->hidden.androidio.fd, (off_t)
ctx->hidden.androidio.offset, SEEK_SET);
1870 ctx->hidden.androidio.assetFileDescriptorRef =
NULL;
1873 mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, assetManager),
1874 "open",
"(Ljava/lang/String;I)Ljava/io/InputStream;");
1875 inputStream = (*env)->CallObjectMethod(env, assetManager, mid, fileNameJString, 1 );
1876 if (Android_JNI_ExceptionOccurred(
SDL_FALSE)) {
1878 inputStream = (*env)->CallStaticObjectMethod(env, mActivityClass, midOpenAPKExpansionInputStream, fileNameJString);
1883 if (Android_JNI_ExceptionOccurred(
SDL_FALSE) || !inputStream) {
1888 ctx->hidden.androidio.inputStreamRef = (*env)->NewGlobalRef(env, inputStream);
1898 mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, inputStream),
1899 "available",
"()I");
1900 ctx->hidden.androidio.size = (long)(*env)->CallIntMethod(env, inputStream, mid);
1901 if (Android_JNI_ExceptionOccurred(
SDL_FALSE)) {
1906 channels = (*env)->FindClass(env,
"java/nio/channels/Channels");
1907 mid = (*env)->GetStaticMethodID(env, channels,
1909 "(Ljava/io/InputStream;)Ljava/nio/channels/ReadableByteChannel;");
1910 readableByteChannel = (*env)->CallStaticObjectMethod(
1911 env, channels, mid, inputStream);
1912 if (Android_JNI_ExceptionOccurred(
SDL_FALSE)) {
1916 ctx->hidden.androidio.readableByteChannelRef =
1917 (*env)->NewGlobalRef(env, readableByteChannel);
1920 mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, readableByteChannel),
1921 "read",
"(Ljava/nio/ByteBuffer;)I");
1922 ctx->hidden.androidio.readMethod = mid;
1929 (*env)->DeleteGlobalRef(env, (jobject)
ctx->hidden.androidio.fileNameRef);
1931 if(
ctx->hidden.androidio.inputStreamRef !=
NULL) {
1932 (*env)->DeleteGlobalRef(env, (jobject)
ctx->hidden.androidio.inputStreamRef);
1935 if(
ctx->hidden.androidio.readableByteChannelRef !=
NULL) {
1936 (*env)->DeleteGlobalRef(env, (jobject)
ctx->hidden.androidio.readableByteChannelRef);
1939 if(
ctx->hidden.androidio.assetFileDescriptorRef !=
NULL) {
1940 (*env)->DeleteGlobalRef(env, (jobject)
ctx->hidden.androidio.assetFileDescriptorRef);
1945 LocalReferenceHolder_Cleanup(&refs);
1950 const char *fileName,
const char *
mode)
1952 struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
1955 jstring fileNameJString;
1957 if (!LocalReferenceHolder_Init(&refs, env)) {
1958 LocalReferenceHolder_Cleanup(&refs);
1963 LocalReferenceHolder_Cleanup(&refs);
1967 fileNameJString = (*env)->NewStringUTF(env, fileName);
1968 ctx->hidden.androidio.fileNameRef = (*env)->NewGlobalRef(env, fileNameJString);
1969 ctx->hidden.androidio.inputStreamRef =
NULL;
1970 ctx->hidden.androidio.readableByteChannelRef =
NULL;
1971 ctx->hidden.androidio.readMethod =
NULL;
1972 ctx->hidden.androidio.assetFileDescriptorRef =
NULL;
1974 retval = Internal_Android_JNI_FileOpen(
ctx);
1975 LocalReferenceHolder_Cleanup(&refs);
1980 size_t size,
size_t maxnum)
1982 struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
1984 if (
ctx->hidden.androidio.assetFileDescriptorRef) {
1985 size_t bytesMax =
size * maxnum;
1987 if (
ctx->hidden.androidio.size != -1 &&
ctx->hidden.androidio.position + bytesMax >
ctx->hidden.androidio.size) {
1988 bytesMax =
ctx->hidden.androidio.size -
ctx->hidden.androidio.position;
1992 ctx->hidden.androidio.position +=
result;
1993 LocalReferenceHolder_Cleanup(&refs);
1996 LocalReferenceHolder_Cleanup(&refs);
1999 jlong bytesRemaining = (jlong) (
size * maxnum);
2000 jlong bytesMax = (jlong) (
ctx->hidden.androidio.size -
ctx->hidden.androidio.position);
2003 jobject readableByteChannel;
2004 jmethodID readMethod;
2008 if (bytesRemaining > bytesMax) bytesRemaining = bytesMax;
2011 if (!LocalReferenceHolder_Init(&refs, env)) {
2012 LocalReferenceHolder_Cleanup(&refs);
2016 readableByteChannel = (jobject)
ctx->hidden.androidio.readableByteChannelRef;
2017 readMethod = (jmethodID)
ctx->hidden.androidio.readMethod;
2018 byteBuffer = (*env)->NewDirectByteBuffer(env,
buffer, bytesRemaining);
2020 while (bytesRemaining > 0) {
2022 int result = (*env)->CallIntMethod(env, readableByteChannel, readMethod, byteBuffer);
2024 if (Android_JNI_ExceptionOccurred(
SDL_FALSE)) {
2025 LocalReferenceHolder_Cleanup(&refs);
2033 bytesRemaining -=
result;
2035 ctx->hidden.androidio.position +=
result;
2037 LocalReferenceHolder_Cleanup(&refs);
2038 return bytesRead /
size;
2045 SDL_SetError(
"Cannot write to Android package filesystem");
2051 struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
2056 if (!LocalReferenceHolder_Init(&refs, env)) {
2057 LocalReferenceHolder_Cleanup(&refs);
2058 return SDL_SetError(
"Failed to allocate enough JVM local references");
2063 (*env)->DeleteGlobalRef(env, (jobject)
ctx->hidden.androidio.fileNameRef);
2066 if (
ctx->hidden.androidio.assetFileDescriptorRef) {
2067 jobject inputStream = (jobject)
ctx->hidden.androidio.assetFileDescriptorRef;
2068 jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, inputStream),
2070 (*env)->CallVoidMethod(env, inputStream, mid);
2071 (*env)->DeleteGlobalRef(env, (jobject)
ctx->hidden.androidio.assetFileDescriptorRef);
2072 if (Android_JNI_ExceptionOccurred(
SDL_FALSE)) {
2077 jobject inputStream = (jobject)
ctx->hidden.androidio.inputStreamRef;
2080 jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, inputStream),
2082 (*env)->CallVoidMethod(env, inputStream, mid);
2083 (*env)->DeleteGlobalRef(env, (jobject)
ctx->hidden.androidio.inputStreamRef);
2084 (*env)->DeleteGlobalRef(env, (jobject)
ctx->hidden.androidio.readableByteChannelRef);
2085 if (Android_JNI_ExceptionOccurred(
SDL_FALSE)) {
2095 LocalReferenceHolder_Cleanup(&refs);
2102 return ctx->hidden.androidio.size;
2107 if (
ctx->hidden.androidio.assetFileDescriptorRef) {
2111 if (
ctx->hidden.androidio.size != -1 &&
offset >
ctx->hidden.androidio.size)
offset =
ctx->hidden.androidio.size;
2115 offset +=
ctx->hidden.androidio.position;
2116 if (
ctx->hidden.androidio.size != -1 &&
offset >
ctx->hidden.androidio.size)
offset =
ctx->hidden.androidio.size;
2126 ret = lseek(
ctx->hidden.androidio.fd, (off_t)
offset, SEEK_SET);
2127 if (ret == -1)
return -1;
2128 ctx->hidden.androidio.position = ret -
ctx->hidden.androidio.offset;
2138 newPosition =
ctx->hidden.androidio.position +
offset;
2141 newPosition =
ctx->hidden.androidio.size +
offset;
2148 if (newPosition < 0) {
2151 if (newPosition >
ctx->hidden.androidio.size) {
2152 newPosition =
ctx->hidden.androidio.size;
2155 movement = newPosition -
ctx->hidden.androidio.position;
2157 unsigned char buffer[4096];
2160 while (movement > 0) {
2163 if (amount > movement) {
2175 }
else if (movement < 0) {
2179 Internal_Android_JNI_FileOpen(
ctx);
2184 return ctx->hidden.androidio.position;
2190 return Internal_Android_JNI_FileClose(
ctx,
SDL_TRUE);
2196 jstring
string = (*env)->NewStringUTF(env,
text);
2197 (*env)->CallStaticVoidMethod(env, mActivityClass, midClipboardSetText,
string);
2198 (*env)->DeleteLocalRef(env,
string);
2208 string = (*env)->CallStaticObjectMethod(env, mActivityClass, midClipboardGetText);
2210 const char *utf = (*env)->GetStringUTFChars(env,
string, 0);
2213 (*env)->ReleaseStringUTFChars(env,
string, utf);
2215 (*env)->DeleteLocalRef(env,
string);
2224 jboolean
retval = (*env)->CallStaticBooleanMethod(env, mActivityClass, midClipboardHasText);
2234 struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
2246 if (!LocalReferenceHolder_Init(&refs, env)) {
2247 LocalReferenceHolder_Cleanup(&refs);
2253 context = (*env)->CallStaticObjectMethod(env, mActivityClass, midGetContext);
2255 action = (*env)->NewStringUTF(env,
"android.intent.action.BATTERY_CHANGED");
2257 cls = (*env)->FindClass(env,
"android/content/IntentFilter");
2259 mid = (*env)->GetMethodID(env, cls,
"<init>",
"(Ljava/lang/String;)V");
2262 (*env)->DeleteLocalRef(env,
action);
2264 mid = (*env)->GetMethodID(env, mActivityClass,
"registerReceiver",
"(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;");
2267 (*env)->DeleteLocalRef(env,
filter);
2269 cls = (*env)->GetObjectClass(env, intent);
2271 imid = (*env)->GetMethodID(env, cls,
"getIntExtra",
"(Ljava/lang/String;I)I");
2274 #define GET_INT_EXTRA(var, key) \
2276 iname = (*env)->NewStringUTF(env, key); \
2277 (var) = (*env)->CallIntMethod(env, intent, imid, iname, -1); \
2278 (*env)->DeleteLocalRef(env, iname);
2280 bmid = (*env)->GetMethodID(env, cls,
"getBooleanExtra",
"(Ljava/lang/String;Z)Z");
2283 #define GET_BOOL_EXTRA(var, key) \
2285 bname = (*env)->NewStringUTF(env, key); \
2286 (var) = (*env)->CallBooleanMethod(env, intent, bmid, bname, JNI_FALSE); \
2287 (*env)->DeleteLocalRef(env, bname);
2291 GET_INT_EXTRA(plug,
"plugged")
2293 LocalReferenceHolder_Cleanup(&refs);
2298 *plugged = (0 < plug) ? 1 : 0;
2303 GET_INT_EXTRA(status,
"status")
2305 LocalReferenceHolder_Cleanup(&refs);
2309 *charged = (status == 5) ? 1 : 0;
2313 GET_BOOL_EXTRA(present,
"present")
2314 *battery = present ? 1 : 0;
2327 GET_INT_EXTRA(level_temp,
"level")
2332 GET_INT_EXTRA(scale_temp,
"scale")
2337 LocalReferenceHolder_Cleanup(&refs);
2343 (*env)->DeleteLocalRef(env, intent);
2345 LocalReferenceHolder_Cleanup(&refs);
2352 (*env)->CallStaticVoidMethod(env, mActivityClass, midInitTouch);
2358 (*env)->CallStaticVoidMethod(env, mControllerManagerClass, midPollInputDevices);
2364 (*env)->CallStaticVoidMethod(env, mControllerManagerClass, midPollHapticDevices);
2370 (*env)->CallStaticVoidMethod(env, mControllerManagerClass, midHapticRun, device_id, intensity,
length);
2376 (*env)->CallStaticVoidMethod(env, mControllerManagerClass, midHapticStop, device_id);
2380 #define COMMAND_SET_KEEP_SCREEN_ON 5
2387 success = (*env)->CallStaticBooleanMethod(env, mActivityClass, midSendMessage, command,
param);
2388 return success ? 0 : -1;
2399 (*env)->CallStaticBooleanMethod(env, mActivityClass, midShowTextInput,
2409 const int COMMAND_TEXTEDIT_HIDE = 3;
2416 jboolean is_shown = 0;
2417 is_shown = (*env)->CallStaticBooleanMethod(env, mActivityClass, midIsScreenKeyboardShown);
2430 jintArray button_flags;
2431 jintArray button_ids;
2432 jobjectArray button_texts;
2442 clazz = (*env)->FindClass(env,
"java/lang/String");
2444 title = (*env)->NewStringUTF(env, messageboxdata->
title);
2447 button_flags = (*env)->NewIntArray(env, messageboxdata->
numbuttons);
2448 button_ids = (*env)->NewIntArray(env, messageboxdata->
numbuttons);
2449 button_texts = (*env)->NewObjectArray(env, messageboxdata->
numbuttons,
2457 sdlButton = &messageboxdata->
buttons[
i];
2460 temp = sdlButton->
flags;
2461 (*env)->SetIntArrayRegion(env, button_flags,
i, 1, &temp);
2463 (*env)->SetIntArrayRegion(env, button_ids,
i, 1, &temp);
2464 text = (*env)->NewStringUTF(env, sdlButton->
text);
2465 (*env)->SetObjectArrayElement(env, button_texts,
i,
text);
2466 (*env)->DeleteLocalRef(env,
text);
2472 temp = (0xFFU << 24) |
2476 (*env)->SetIntArrayRegion(env,
colors,
i, 1, &temp);
2482 (*env)->DeleteLocalRef(env, clazz);
2485 context = (*env)->CallStaticObjectMethod(env, mActivityClass, midGetContext);
2487 clazz = (*env)->GetObjectClass(env,
context);
2489 mid = (*env)->GetMethodID(env, clazz,
2490 "messageboxShowMessageBox",
"(ILjava/lang/String;Ljava/lang/String;[I[I[Ljava/lang/String;[I)I");
2491 *buttonid = (*env)->CallIntMethod(env,
context, mid,
2492 messageboxdata->
flags,
2500 (*env)->DeleteLocalRef(env,
context);
2501 (*env)->DeleteLocalRef(env, clazz);
2505 (*env)->DeleteLocalRef(env, title);
2506 (*env)->DeleteLocalRef(env,
message);
2507 (*env)->DeleteLocalRef(env, button_flags);
2508 (*env)->DeleteLocalRef(env, button_ids);
2509 (*env)->DeleteLocalRef(env, button_texts);
2510 (*env)->DeleteLocalRef(env,
colors);
2518 // Functions exposed to SDL applications in SDL_system.h
2537 return (*env)->CallStaticObjectMethod(env, mActivityClass, midGetContext);
2542 static int sdk_version;
2544 char sdk[PROP_VALUE_MAX] = {0};
2545 if (__system_property_get(
"ro.build.version.sdk", sdk) != 0) {
2555 return (*env)->CallStaticBooleanMethod(env, mActivityClass, midIsTablet);
2561 return (*env)->CallStaticBooleanMethod(env, mActivityClass, midIsAndroidTV);
2567 return (*env)->CallStaticBooleanMethod(env, mActivityClass, midIsChromebook);
2573 return (*env)->CallStaticBooleanMethod(env, mActivityClass, midIsDeXMode);
2579 (*env)->CallStaticVoidMethod(env, mActivityClass, midManualBackButton);
2584 static char *s_AndroidInternalFilesPath =
NULL;
2586 if (!s_AndroidInternalFilesPath) {
2587 struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
2595 if (!LocalReferenceHolder_Init(&refs, env)) {
2596 LocalReferenceHolder_Cleanup(&refs);
2601 context = (*env)->CallStaticObjectMethod(env, mActivityClass, midGetContext);
2604 LocalReferenceHolder_Cleanup(&refs);
2609 mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env,
context),
2610 "getFilesDir",
"()Ljava/io/File;");
2611 fileObject = (*env)->CallObjectMethod(env,
context, mid);
2614 LocalReferenceHolder_Cleanup(&refs);
2619 mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, fileObject),
2620 "getCanonicalPath",
"()Ljava/lang/String;");
2621 pathString = (jstring)(*env)->CallObjectMethod(env, fileObject, mid);
2622 if (Android_JNI_ExceptionOccurred(
SDL_FALSE)) {
2623 LocalReferenceHolder_Cleanup(&refs);
2631 LocalReferenceHolder_Cleanup(&refs);
2633 return s_AndroidInternalFilesPath;
2638 struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
2641 jstring stateString;
2646 if (!LocalReferenceHolder_Init(&refs, env)) {
2647 LocalReferenceHolder_Cleanup(&refs);
2651 cls = (*env)->FindClass(env,
"android/os/Environment");
2652 mid = (*env)->GetStaticMethodID(env, cls,
2653 "getExternalStorageState",
"()Ljava/lang/String;");
2654 stateString = (jstring)(*env)->CallStaticObjectMethod(env, cls, mid);
2656 state = (*env)->GetStringUTFChars(env, stateString,
NULL);
2659 __android_log_print(ANDROID_LOG_INFO,
"SDL",
"external storage state: %s",
state);
2662 stateFlags = SDL_ANDROID_EXTERNAL_STORAGE_READ |
2663 SDL_ANDROID_EXTERNAL_STORAGE_WRITE;
2665 stateFlags = SDL_ANDROID_EXTERNAL_STORAGE_READ;
2669 (*env)->ReleaseStringUTFChars(env, stateString,
state);
2671 LocalReferenceHolder_Cleanup(&refs);
2677 static char *s_AndroidExternalFilesPath =
NULL;
2679 if (!s_AndroidExternalFilesPath) {
2680 struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
2688 if (!LocalReferenceHolder_Init(&refs, env)) {
2689 LocalReferenceHolder_Cleanup(&refs);
2694 context = (*env)->CallStaticObjectMethod(env, mActivityClass, midGetContext);
2697 mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env,
context),
2698 "getExternalFilesDir",
"(Ljava/lang/String;)Ljava/io/File;");
2699 fileObject = (*env)->CallObjectMethod(env,
context, mid,
NULL);
2702 LocalReferenceHolder_Cleanup(&refs);
2707 mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, fileObject),
2708 "getAbsolutePath",
"()Ljava/lang/String;");
2709 pathString = (jstring)(*env)->CallObjectMethod(env, fileObject, mid);
2715 LocalReferenceHolder_Cleanup(&refs);
2717 return s_AndroidExternalFilesPath;
2722 if (!mActivityClass || !midGetManifestEnvironmentVariables) {
2723 __android_log_print(ANDROID_LOG_WARN,
"SDL",
"Request to get environment variables before JNI is ready");
2727 if (!bHasEnvironmentVariables) {
2729 SDL_bool ret = (*env)->CallStaticBooleanMethod(env, mActivityClass, midGetManifestEnvironmentVariables);
2731 bHasEnvironmentVariables =
SDL_TRUE;
2739 int custom_cursor = 0;
2744 custom_cursor = (*env)->CallStaticIntMethod(env, mActivityClass, midCreateCustomCursor,
pixels,
surface->w,
surface->h,
hot_x, hot_y);
2745 (*env)->DeleteLocalRef(env,
pixels);
2749 return custom_cursor;
2756 return (*env)->CallStaticBooleanMethod(env, mActivityClass, midSetCustomCursor, cursorID);
2762 return (*env)->CallStaticBooleanMethod(env, mActivityClass, midSetSystemCursor, cursorID);
2768 return (*env)->CallStaticBooleanMethod(env, mActivityClass, midSupportsRelativeMouse);
2774 return (*env)->CallStaticBooleanMethod(env, mActivityClass, midSetRelativeMouseEnabled, (
enabled == 1));
2780 const int requestCode = 1;
2788 jstring jpermission = (*env)->NewStringUTF(env, permission);
2789 (*env)->CallStaticVoidMethod(env, mActivityClass, midRequestPermission, jpermission, requestCode);
2790 (*env)->DeleteLocalRef(env, jpermission);
2796 return bPermissionRequestResult;