22 #include "SDL_stdinc.h"
33 #include "../../events/SDL_events_c.h"
34 #include "../../video/android/SDL_androidkeyboard.h"
35 #include "../../video/android/SDL_androidtouch.h"
36 #include "../../video/android/SDL_androidvideo.h"
38 #include <android/log.h>
42 #define LOG_TAG "SDL_android"
45 #define LOGI(...) do {} while (false)
46 #define LOGE(...) do {} while (false)
52 extern void Android_RunAudioThread();
54 static void Android_JNI_ThreadDestroyed(
void*);
61 #include <android/log.h>
67 static pthread_key_t mThreadKey;
68 static JavaVM* mJavaVM;
71 static jclass mActivityClass;
74 static jmethodID midCreateGLContext;
75 static jmethodID midFlipBuffers;
76 static jmethodID midAudioInit;
77 static jmethodID midAudioWriteShortBuffer;
78 static jmethodID midAudioWriteByteBuffer;
79 static jmethodID midAudioQuit;
82 static float fLastAccelerometer[3];
83 static bool bHasNewData;
90 extern "C" jint JNI_OnLoad(JavaVM* vm,
void* reserved)
94 LOGI(
"JNI_OnLoad called");
95 if (mJavaVM->GetEnv((
void**) &env, JNI_VERSION_1_4) != JNI_OK) {
96 LOGE(
"Failed to get the environment using GetEnv()");
103 if (pthread_key_create(&mThreadKey, Android_JNI_ThreadDestroyed)) {
104 __android_log_print(ANDROID_LOG_ERROR,
"SDL",
"Error initializing pthread key");
110 return JNI_VERSION_1_4;
114 extern "C" void SDL_Android_Init(JNIEnv* mEnv, jclass cls)
116 __android_log_print(ANDROID_LOG_INFO,
"SDL",
"SDL_Android_Init()");
120 mActivityClass = (jclass)mEnv->NewGlobalRef(cls);
122 midCreateGLContext = mEnv->GetStaticMethodID(mActivityClass,
123 "createGLContext",
"(II[I)Z");
124 midFlipBuffers = mEnv->GetStaticMethodID(mActivityClass,
125 "flipBuffers",
"()V");
126 midAudioInit = mEnv->GetStaticMethodID(mActivityClass,
127 "audioInit",
"(IZZI)V");
128 midAudioWriteShortBuffer = mEnv->GetStaticMethodID(mActivityClass,
129 "audioWriteShortBuffer",
"([S)V");
130 midAudioWriteByteBuffer = mEnv->GetStaticMethodID(mActivityClass,
131 "audioWriteByteBuffer",
"([B)V");
132 midAudioQuit = mEnv->GetStaticMethodID(mActivityClass,
137 if(!midCreateGLContext || !midFlipBuffers || !midAudioInit ||
138 !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit) {
139 __android_log_print(ANDROID_LOG_WARN,
"SDL",
"SDL: Couldn't locate Java callbacks, check that they're named and typed correctly");
141 __android_log_print(ANDROID_LOG_INFO,
"SDL",
"SDL_Android_Init() finished!");
145 extern "C" void Java_org_libsdl_app_SDLActivity_onNativeResize(
146 JNIEnv* env, jclass jcls,
153 extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyDown(
154 JNIEnv* env, jclass jcls, jint keycode)
160 extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyUp(
161 JNIEnv* env, jclass jcls, jint keycode)
167 extern "C" void Java_org_libsdl_app_SDLActivity_onNativeTouch(
168 JNIEnv* env, jclass jcls,
169 jint touch_device_id_in, jint pointer_finger_id_in,
170 jint action, jfloat
x, jfloat
y, jfloat
p)
172 Android_OnTouch(touch_device_id_in, pointer_finger_id_in, action, x, y, p);
176 extern "C" void Java_org_libsdl_app_SDLActivity_onNativeAccel(
177 JNIEnv* env, jclass jcls,
178 jfloat
x, jfloat
y, jfloat
z)
180 fLastAccelerometer[0] =
x;
181 fLastAccelerometer[1] =
y;
182 fLastAccelerometer[2] =
z;
187 extern "C" void Java_org_libsdl_app_SDLActivity_nativeLowMemory(
188 JNIEnv* env, jclass cls)
194 extern "C" void Java_org_libsdl_app_SDLActivity_nativeQuit(
195 JNIEnv* env, jclass cls)
203 extern "C" void Java_org_libsdl_app_SDLActivity_nativePause(
204 JNIEnv* env, jclass cls)
213 __android_log_print(ANDROID_LOG_VERBOSE,
"SDL",
"nativePause()");
219 extern "C" void Java_org_libsdl_app_SDLActivity_nativeResume(
220 JNIEnv* env, jclass cls)
222 __android_log_print(ANDROID_LOG_VERBOSE,
"SDL",
"nativeResume()");
237 extern "C" void Java_org_libsdl_app_SDLActivity_nativeRunAudioThread(
238 JNIEnv* env, jclass cls)
243 Android_RunAudioThread();
246 extern "C" void Java_org_libsdl_app_SDLInputConnection_nativeCommitText(
247 JNIEnv* env, jclass cls,
248 jstring text, jint newCursorPosition)
250 const char *utftext = env->GetStringUTFChars(text,
NULL);
254 env->ReleaseStringUTFChars(text, utftext);
257 extern "C" void Java_org_libsdl_app_SDLInputConnection_nativeSetComposingText(
258 JNIEnv* env, jclass cls,
259 jstring text, jint newCursorPosition)
261 const char *utftext = env->GetStringUTFChars(text,
NULL);
265 env->ReleaseStringUTFChars(text, utftext);
274 class LocalReferenceHolder
280 static bool IsActive() {
285 LocalReferenceHolder(
const char *
func) : m_env(
NULL), m_func(func) {
287 SDL_Log(
"Entering function %s", m_func);
290 ~LocalReferenceHolder() {
292 SDL_Log(
"Leaving function %s", m_func);
295 m_env->PopLocalFrame(
NULL);
300 bool init(JNIEnv *env, jint capacity = 16) {
301 if (env->PushLocalFrame(capacity) < 0) {
302 SDL_SetError(
"Failed to allocate enough JVM local references");
314 int LocalReferenceHolder::s_active;
316 extern "C" SDL_bool Android_JNI_CreateContext(
int majorVersion,
int minorVersion,
340 array = env->NewIntArray(len);
341 env->SetIntArrayRegion(array, 0, len, attribs);
343 jboolean success = env->CallStaticBooleanMethod(mActivityClass, midCreateGLContext, majorVersion, minorVersion, array);
345 env->DeleteLocalRef(array);
353 mEnv->CallStaticVoidMethod(mActivityClass, midFlipBuffers);
360 mid = mEnv->GetStaticMethodID(mActivityClass,
"setActivityTitle",
"(Ljava/lang/String;)Z");
362 jstring jtitle =
reinterpret_cast<jstring
>(mEnv->NewStringUTF(title));
363 mEnv->CallStaticBooleanMethod(mActivityClass, mid, jtitle);
364 mEnv->DeleteLocalRef(jtitle);
374 for (i = 0; i < 3; ++
i) {
375 values[
i] = fLastAccelerometer[
i];
384 static void Android_JNI_ThreadDestroyed(
void*
value) {
386 JNIEnv *env = (JNIEnv*) value;
388 mJavaVM->DetachCurrentThread();
389 pthread_setspecific(mThreadKey,
NULL);
407 int status = mJavaVM->AttachCurrentThread(&env,
NULL);
409 LOGE(
"failed to attach current thread");
427 pthread_setspecific(mThreadKey, (
void*) env);
434 static jboolean audioBuffer16Bit = JNI_FALSE;
435 static jboolean audioBufferStereo = JNI_FALSE;
436 static jobject audioBuffer =
NULL;
437 static void* audioBufferPinned =
NULL;
441 int audioBufferFrames;
446 LOGE(
"callback_handler: failed to attach current thread");
450 __android_log_print(ANDROID_LOG_VERBOSE,
"SDL",
"SDL audio: opening device");
451 audioBuffer16Bit = is16Bit;
452 audioBufferStereo = channelCount > 1;
454 env->CallStaticVoidMethod(mActivityClass, midAudioInit, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames);
460 jshortArray audioBufferLocal = env->NewShortArray(desiredBufferFrames * (audioBufferStereo ? 2 : 1));
461 if (audioBufferLocal) {
462 audioBuffer = env->NewGlobalRef(audioBufferLocal);
463 env->DeleteLocalRef(audioBufferLocal);
467 jbyteArray audioBufferLocal = env->NewByteArray(desiredBufferFrames * (audioBufferStereo ? 2 : 1));
468 if (audioBufferLocal) {
469 audioBuffer = env->NewGlobalRef(audioBufferLocal);
470 env->DeleteLocalRef(audioBufferLocal);
474 if (audioBuffer ==
NULL) {
475 __android_log_print(ANDROID_LOG_WARN,
"SDL",
"SDL audio: could not allocate an audio buffer!");
479 jboolean isCopy = JNI_FALSE;
480 if (audioBuffer16Bit) {
481 audioBufferPinned = env->GetShortArrayElements((jshortArray)audioBuffer, &isCopy);
482 audioBufferFrames = env->GetArrayLength((jshortArray)audioBuffer);
484 audioBufferPinned = env->GetByteArrayElements((jbyteArray)audioBuffer, &isCopy);
485 audioBufferFrames = env->GetArrayLength((jbyteArray)audioBuffer);
487 if (audioBufferStereo) {
488 audioBufferFrames /= 2;
491 return audioBufferFrames;
496 return audioBufferPinned;
503 if (audioBuffer16Bit) {
504 mAudioEnv->ReleaseShortArrayElements((jshortArray)audioBuffer, (jshort *)audioBufferPinned, JNI_COMMIT);
505 mAudioEnv->CallStaticVoidMethod(mActivityClass, midAudioWriteShortBuffer, (jshortArray)audioBuffer);
507 mAudioEnv->ReleaseByteArrayElements((jbyteArray)audioBuffer, (jbyte *)audioBufferPinned, JNI_COMMIT);
508 mAudioEnv->CallStaticVoidMethod(mActivityClass, midAudioWriteByteBuffer, (jbyteArray)audioBuffer);
518 env->CallStaticVoidMethod(mActivityClass, midAudioQuit);
521 env->DeleteGlobalRef(audioBuffer);
523 audioBufferPinned =
NULL;
529 static bool Android_JNI_ExceptionOccurred(
bool silent =
false)
534 jthrowable exception = mEnv->ExceptionOccurred();
535 if (exception !=
NULL) {
539 mEnv->ExceptionClear();
542 jclass exceptionClass = mEnv->GetObjectClass(exception);
543 jclass classClass = mEnv->FindClass(
"java/lang/Class");
545 mid = mEnv->GetMethodID(classClass,
"getName",
"()Ljava/lang/String;");
546 jstring exceptionName = (jstring)mEnv->CallObjectMethod(exceptionClass, mid);
547 const char* exceptionNameUTF8 = mEnv->GetStringUTFChars(exceptionName, 0);
549 mid = mEnv->GetMethodID(exceptionClass,
"getMessage",
"()Ljava/lang/String;");
550 jstring exceptionMessage = (jstring)mEnv->CallObjectMethod(exception, mid);
552 if (exceptionMessage !=
NULL) {
553 const char* exceptionMessageUTF8 = mEnv->GetStringUTFChars(exceptionMessage, 0);
554 SDL_SetError(
"%s: %s", exceptionNameUTF8, exceptionMessageUTF8);
555 mEnv->ReleaseStringUTFChars(exceptionMessage, exceptionMessageUTF8);
560 mEnv->ReleaseStringUTFChars(exceptionName, exceptionNameUTF8);
571 LocalReferenceHolder refs(__FUNCTION__);
576 jobject assetManager;
579 jobject readableByteChannel;
580 jstring fileNameJString;
586 if (!refs.init(mEnv)) {
590 fileNameJString = (jstring)ctx->
hidden.androidio.fileNameRef;
591 ctx->
hidden.androidio.position = 0;
594 mid = mEnv->GetStaticMethodID(mActivityClass,
595 "getContext",
"()Landroid/content/Context;");
596 context = mEnv->CallStaticObjectMethod(mActivityClass, mid);
600 mid = mEnv->GetMethodID(mEnv->GetObjectClass(context),
601 "getAssets",
"()Landroid/content/res/AssetManager;");
602 assetManager = mEnv->CallObjectMethod(context, mid);
607 mid = mEnv->GetMethodID(mEnv->GetObjectClass(assetManager),
"openFd",
"(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;");
608 inputStream = mEnv->CallObjectMethod(assetManager, mid, fileNameJString);
609 if (Android_JNI_ExceptionOccurred(
true)) {
613 mid = mEnv->GetMethodID(mEnv->GetObjectClass(inputStream),
"getStartOffset",
"()J");
614 ctx->
hidden.androidio.
offset = mEnv->CallLongMethod(inputStream, mid);
615 if (Android_JNI_ExceptionOccurred(
true)) {
619 mid = mEnv->GetMethodID(mEnv->GetObjectClass(inputStream),
"getDeclaredLength",
"()J");
620 ctx->
hidden.androidio.
size = mEnv->CallLongMethod(inputStream, mid);
621 if (Android_JNI_ExceptionOccurred(
true)) {
625 mid = mEnv->GetMethodID(mEnv->GetObjectClass(inputStream),
"getFileDescriptor",
"()Ljava/io/FileDescriptor;");
626 fd = mEnv->CallObjectMethod(inputStream, mid);
627 fdCls = mEnv->GetObjectClass(fd);
628 descriptor = mEnv->GetFieldID(fdCls,
"descriptor",
"I");
629 ctx->
hidden.androidio.fd = mEnv->GetIntField(fd, descriptor);
630 ctx->
hidden.androidio.assetFileDescriptorRef = mEnv->NewGlobalRef(inputStream);
641 ctx->
hidden.androidio.assetFileDescriptorRef =
NULL;
644 mid = mEnv->GetMethodID(mEnv->GetObjectClass(assetManager),
645 "open",
"(Ljava/lang/String;I)Ljava/io/InputStream;");
646 inputStream = mEnv->CallObjectMethod(assetManager, mid, fileNameJString, 1 );
647 if (Android_JNI_ExceptionOccurred()) {
651 ctx->
hidden.androidio.inputStreamRef = mEnv->NewGlobalRef(inputStream);
660 mid = mEnv->GetMethodID(mEnv->GetObjectClass(inputStream),
662 ctx->
hidden.androidio.
size = (long)mEnv->CallIntMethod(inputStream, mid);
663 if (Android_JNI_ExceptionOccurred()) {
668 channels = mEnv->FindClass(
"java/nio/channels/Channels");
669 mid = mEnv->GetStaticMethodID(channels,
671 "(Ljava/io/InputStream;)Ljava/nio/channels/ReadableByteChannel;");
672 readableByteChannel = mEnv->CallStaticObjectMethod(
673 channels, mid, inputStream);
674 if (Android_JNI_ExceptionOccurred()) {
678 ctx->
hidden.androidio.readableByteChannelRef =
679 mEnv->NewGlobalRef(readableByteChannel);
682 mid = mEnv->GetMethodID(mEnv->GetObjectClass(readableByteChannel),
683 "read",
"(Ljava/nio/ByteBuffer;)I");
684 ctx->
hidden.androidio.readMethod = mid;
691 mEnv->DeleteGlobalRef((jobject)ctx->
hidden.androidio.fileNameRef);
693 if(ctx->
hidden.androidio.inputStreamRef !=
NULL) {
694 mEnv->DeleteGlobalRef((jobject)ctx->
hidden.androidio.inputStreamRef);
697 if(ctx->
hidden.androidio.readableByteChannelRef !=
NULL) {
698 mEnv->DeleteGlobalRef((jobject)ctx->
hidden.androidio.readableByteChannelRef);
701 if(ctx->
hidden.androidio.assetFileDescriptorRef !=
NULL) {
702 mEnv->DeleteGlobalRef((jobject)ctx->
hidden.androidio.assetFileDescriptorRef);
711 const char* fileName,
const char*)
713 LocalReferenceHolder refs(__FUNCTION__);
716 if (!refs.init(mEnv)) {
724 jstring fileNameJString = mEnv->NewStringUTF(fileName);
725 ctx->
hidden.androidio.fileNameRef = mEnv->NewGlobalRef(fileNameJString);
727 ctx->
hidden.androidio.readableByteChannelRef =
NULL;
729 ctx->
hidden.androidio.assetFileDescriptorRef =
NULL;
735 size_t size,
size_t maxnum)
737 LocalReferenceHolder refs(__FUNCTION__);
739 if (ctx->
hidden.androidio.assetFileDescriptorRef) {
740 size_t bytesMax = size * maxnum;
744 size_t result = read(ctx->
hidden.androidio.fd, buffer, bytesMax );
747 return result /
size;
751 jlong bytesRemaining = (jlong) (size * maxnum);
752 jlong bytesMax = (jlong) (ctx->
hidden.androidio.
size - ctx->
hidden.androidio.position);
756 if (bytesRemaining > bytesMax) bytesRemaining = bytesMax;
759 if (!refs.init(mEnv)) {
763 jobject readableByteChannel = (jobject)ctx->
hidden.androidio.readableByteChannelRef;
764 jmethodID readMethod = (jmethodID)ctx->
hidden.androidio.readMethod;
765 jobject byteBuffer = mEnv->NewDirectByteBuffer(buffer, bytesRemaining);
767 while (bytesRemaining > 0) {
769 int result = mEnv->CallIntMethod(readableByteChannel, readMethod, byteBuffer);
771 if (Android_JNI_ExceptionOccurred()) {
783 return bytesRead /
size;
788 size_t size,
size_t num)
790 SDL_SetError(
"Cannot write to Android package filesystem");
796 LocalReferenceHolder refs(__FUNCTION__);
800 if (!refs.init(mEnv)) {
801 return SDL_SetError(
"Failed to allocate enough JVM local references");
806 mEnv->DeleteGlobalRef((jobject)ctx->
hidden.androidio.fileNameRef);
809 if (ctx->
hidden.androidio.assetFileDescriptorRef) {
810 jobject inputStream = (jobject)ctx->
hidden.androidio.assetFileDescriptorRef;
811 jmethodID mid = mEnv->GetMethodID(mEnv->GetObjectClass(inputStream),
813 mEnv->CallVoidMethod(inputStream, mid);
814 mEnv->DeleteGlobalRef((jobject)ctx->
hidden.androidio.assetFileDescriptorRef);
815 if (Android_JNI_ExceptionOccurred()) {
820 jobject inputStream = (jobject)ctx->
hidden.androidio.inputStreamRef;
823 jmethodID mid = mEnv->GetMethodID(mEnv->GetObjectClass(inputStream),
825 mEnv->CallVoidMethod(inputStream, mid);
826 mEnv->DeleteGlobalRef((jobject)ctx->
hidden.androidio.inputStreamRef);
827 mEnv->DeleteGlobalRef((jobject)ctx->
hidden.androidio.readableByteChannelRef);
828 if (Android_JNI_ExceptionOccurred()) {
849 if (ctx->
hidden.androidio.assetFileDescriptorRef) {
856 offset += ctx->
hidden.androidio.position;
869 if (ret == -1)
return -1;
889 if (newPosition < 0) {
892 if (newPosition > ctx->
hidden.androidio.
size) {
896 Sint64 movement = newPosition - ctx->
hidden.androidio.position;
898 unsigned char buffer[4096];
901 while (movement > 0) {
903 if (amount > movement) {
915 }
else if (movement < 0) {
924 return ctx->
hidden.androidio.position;
934 static jobject Android_JNI_GetSystemServiceObject(
const char*
name)
936 LocalReferenceHolder refs(__FUNCTION__);
938 if (!refs.init(env)) {
942 jstring service = env->NewStringUTF(name);
946 mid = env->GetStaticMethodID(mActivityClass,
"getContext",
"()Landroid/content/Context;");
947 jobject context = env->CallStaticObjectMethod(mActivityClass, mid);
949 mid = env->GetMethodID(mActivityClass,
"getSystemService",
"(Ljava/lang/String;)Ljava/lang/Object;");
950 jobject manager = env->CallObjectMethod(context, mid, service);
952 env->DeleteLocalRef(service);
954 return manager ? env->NewGlobalRef(manager) :
NULL;
957 #define SETUP_CLIPBOARD(error) \
958 LocalReferenceHolder refs(__FUNCTION__); \
959 JNIEnv* env = Android_JNI_GetEnv(); \
960 if (!refs.init(env)) { \
963 jobject clipboard = Android_JNI_GetSystemServiceObject("clipboard"); \
972 jmethodID mid = env->GetMethodID(env->GetObjectClass(clipboard), "setText", "(Ljava/lang/CharSequence;)V");
973 jstring
string = env->NewStringUTF(text);
974 env->CallVoidMethod(clipboard, mid,
string);
975 env->DeleteGlobalRef(clipboard);
976 env->DeleteLocalRef(
string);
984 jmethodID mid = env->GetMethodID(env->GetObjectClass(clipboard), "getText", "()Ljava/lang/CharSequence;");
985 jobject sequence = env->CallObjectMethod(clipboard, mid);
986 env->DeleteGlobalRef(clipboard);
988 mid = env->GetMethodID(env->GetObjectClass(sequence),
"toString",
"()Ljava/lang/String;");
989 jstring
string =
reinterpret_cast<jstring
>(env->CallObjectMethod(sequence, mid));
990 const char* utf = env->GetStringUTFChars(
string, 0);
993 env->ReleaseStringUTFChars(
string, utf);
1004 jmethodID mid = env->GetMethodID(env->GetObjectClass(clipboard), "hasText", "()Z");
1005 jboolean has = env->CallBooleanMethod(clipboard, mid);
1006 env->DeleteGlobalRef(clipboard);
1016 LocalReferenceHolder refs(__FUNCTION__);
1018 if (!refs.init(env)) {
1024 mid = env->GetStaticMethodID(mActivityClass,
"getContext",
"()Landroid/content/Context;");
1025 jobject context = env->CallStaticObjectMethod(mActivityClass, mid);
1027 jstring action = env->NewStringUTF(
"android.intent.action.BATTERY_CHANGED");
1029 jclass cls = env->FindClass(
"android/content/IntentFilter");
1031 mid = env->GetMethodID(cls,
"<init>",
"(Ljava/lang/String;)V");
1032 jobject
filter = env->NewObject(cls, mid, action);
1034 env->DeleteLocalRef(action);
1036 mid = env->GetMethodID(mActivityClass,
"registerReceiver",
"(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;");
1037 jobject intent = env->CallObjectMethod(context, mid,
NULL, filter);
1039 env->DeleteLocalRef(filter);
1041 cls = env->GetObjectClass(intent);
1044 jmethodID imid = env->GetMethodID(cls,
"getIntExtra",
"(Ljava/lang/String;I)I");
1046 #define GET_INT_EXTRA(var, key) \
1047 iname = env->NewStringUTF(key); \
1048 int var = env->CallIntMethod(intent, imid, iname, -1); \
1049 env->DeleteLocalRef(iname);
1052 jmethodID bmid = env->GetMethodID(cls,
"getBooleanExtra",
"(Ljava/lang/String;Z)Z");
1054 #define GET_BOOL_EXTRA(var, key) \
1055 bname = env->NewStringUTF(key); \
1056 int var = env->CallBooleanMethod(intent, bmid, bname, JNI_FALSE); \
1057 env->DeleteLocalRef(bname);
1060 GET_INT_EXTRA(plug,
"plugged")
1066 *plugged = (0 < plug) ? 1 : 0;
1070 GET_INT_EXTRA(status,
"status")
1075 *charged = (status == 5) ? 1 : 0;
1079 GET_BOOL_EXTRA(present,
"present")
1080 *battery = present ? 1 : 0;
1088 GET_INT_EXTRA(
level,
"level")
1089 GET_INT_EXTRA(
scale, "scale")
1090 if ((
level == -1) || (scale == -1)) {
1096 env->DeleteLocalRef(intent);
1108 jmethodID mid = env->GetStaticMethodID(mActivityClass,
"sendMessage",
"(II)Z");
1112 jboolean success = env->CallStaticBooleanMethod(mActivityClass, mid, command, param);
1113 return success ? 0 : -1;
1123 jmethodID mid = env->GetStaticMethodID(mActivityClass,
"showTextInput",
"(IIII)Z");
1127 env->CallStaticBooleanMethod( mActivityClass, mid,
1137 const int COMMAND_TEXTEDIT_HIDE = 3;
1146 extern "C" void *SDL_AndroidGetJNIEnv()
1153 extern "C" void *SDL_AndroidGetActivity()
1165 mid = env->GetStaticMethodID(mActivityClass,
1166 "getContext",
"()Landroid/content/Context;");
1167 return env->CallStaticObjectMethod(mActivityClass, mid);
1170 extern "C" const char * SDL_AndroidGetInternalStoragePath()
1172 static char *s_AndroidInternalFilesPath =
NULL;
1174 if (!s_AndroidInternalFilesPath) {
1175 LocalReferenceHolder refs(__FUNCTION__);
1183 if (!refs.init(env)) {
1188 mid = env->GetStaticMethodID(mActivityClass,
1189 "getContext",
"()Landroid/content/Context;");
1190 context = env->CallStaticObjectMethod(mActivityClass, mid);
1193 mid = env->GetMethodID(env->GetObjectClass(context),
1194 "getFilesDir",
"()Ljava/io/File;");
1195 fileObject = env->CallObjectMethod(context, mid);
1202 mid = env->GetMethodID(env->GetObjectClass(fileObject),
1203 "getAbsolutePath",
"()Ljava/lang/String;");
1204 pathString = (jstring)env->CallObjectMethod(fileObject, mid);
1206 path = env->GetStringUTFChars(pathString,
NULL);
1207 s_AndroidInternalFilesPath =
SDL_strdup(path);
1208 env->ReleaseStringUTFChars(pathString, path);
1210 return s_AndroidInternalFilesPath;
1213 extern "C" int SDL_AndroidGetExternalStorageState()
1215 LocalReferenceHolder refs(__FUNCTION__);
1218 jstring stateString;
1223 if (!refs.init(env)) {
1227 cls = env->FindClass(
"android/os/Environment");
1228 mid = env->GetStaticMethodID(cls,
1229 "getExternalStorageState",
"()Ljava/lang/String;");
1230 stateString = (jstring)env->CallStaticObjectMethod(cls, mid);
1232 state = env->GetStringUTFChars(stateString,
NULL);
1235 __android_log_print(ANDROID_LOG_INFO,
"SDL",
"external storage state: %s", state);
1238 stateFlags = SDL_ANDROID_EXTERNAL_STORAGE_READ |
1239 SDL_ANDROID_EXTERNAL_STORAGE_WRITE;
1240 }
else if (
SDL_strcmp(state,
"mounted_ro") == 0) {
1241 stateFlags = SDL_ANDROID_EXTERNAL_STORAGE_READ;
1245 env->ReleaseStringUTFChars(stateString, state);
1250 extern "C" const char * SDL_AndroidGetExternalStoragePath()
1252 static char *s_AndroidExternalFilesPath =
NULL;
1254 if (!s_AndroidExternalFilesPath) {
1255 LocalReferenceHolder refs(__FUNCTION__);
1263 if (!refs.init(env)) {
1268 mid = env->GetStaticMethodID(mActivityClass,
1269 "getContext",
"()Landroid/content/Context;");
1270 context = env->CallStaticObjectMethod(mActivityClass, mid);
1273 mid = env->GetMethodID(env->GetObjectClass(context),
1274 "getExternalFilesDir",
"(Ljava/lang/String;)Ljava/io/File;");
1275 fileObject = env->CallObjectMethod(context, mid,
NULL);
1282 mid = env->GetMethodID(env->GetObjectClass(fileObject),
1283 "getAbsolutePath",
"()Ljava/lang/String;");
1284 pathString = (jstring)env->CallObjectMethod(fileObject, mid);
1286 path = env->GetStringUTFChars(pathString,
NULL);
1287 s_AndroidExternalFilesPath =
SDL_strdup(path);
1288 env->ReleaseStringUTFChars(pathString, path);
1290 return s_AndroidExternalFilesPath;
int Android_JNI_FileClose(SDL_RWops *ctx)
int Android_OnKeyUp(int keycode)
int Android_JNI_SendMessage(int command, int param)
void Android_JNI_ShowTextInput(SDL_Rect *inputRect)
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLenum GLsizei const void * pathString
SDL_bool Android_JNI_HasClipboardText()
SDL_bool Android_JNI_GetAccelerometerValues(float values[3])
GLint GLfloat GLint stencil
#define EGL_SAMPLE_BUFFERS
static void init(struct bs2b *bs2b)
void Android_JNI_SetActivityTitle(const char *title)
char * Android_JNI_GetClipboardText()
int Android_OnKeyDown(int keycode)
EGLSurface EGLint EGLint EGLint EGLint height
void Android_OnTouch(int touch_device_id_in, int pointer_finger_id_in, int action, float x, float y, float p)
EGLImageKHR EGLint * name
void Android_JNI_HideTextInput()
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
GLsizei const GLchar *const * path
int Android_JNI_FileOpen(SDL_RWops *ctx, const char *fileName, const char *mode)
SDL_sem * Android_PauseSem
int Android_JNI_SetupThread(void)
EGLContext EGLenum EGLClientBuffer buffer
#define EGL_OPENGL_ES_BIT
EGLSurface EGLint EGLint EGLint width
int SDL_SendKeyboardText(const char *text)
DECLSPEC char *SDLCALL SDL_strdup(const char *str)
DECLSPEC int SDLCALL SDL_Error(SDL_errorcode code)
DECLSPEC Uint32 SDLCALL SDL_SemValue(SDL_sem *sem)
void Android_JNI_CloseAudioDevice()
DECLSPEC void SDLCALL SDL_FreeRW(SDL_RWops *area)
int Android_JNI_GetPowerInfo(int *plugged, int *charged, int *battery, int *seconds, int *percent)
size_t Android_JNI_FileWrite(SDL_RWops *ctx, const void *buffer, size_t size, size_t num)
SDL_Window * Android_Window
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum format
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
void Android_SetScreenResolution(int width, int height, Uint32 format)
GLint GLenum GLsizei GLsizei GLsizei depth
DECLSPEC int SDLCALL SDL_strcmp(const char *str1, const char *str2)
GLclampf GLclampf GLclampf alpha
GLenum GLenum GLenum GLenum GLenum scale
void * Android_JNI_GetAudioBuffer()
#define SDL_assert(condition)
EGLSurface EGLint EGLint y
#define SDL_arraysize(array)
DECLSPEC void SDLCALL SDL_Log(const char *fmt,...)
Log a message with SDL_LOG_CATEGORY_APPLICATION and SDL_LOG_PRIORITY_INFO.
EGLSurface EGLint void ** value
SDL_sem * Android_ResumeSem
size_t Android_JNI_FileRead(SDL_RWops *ctx, void *buffer, size_t size, size_t maxnum)
void Android_JNI_WriteAudioBuffer()
union SDL_RWops::@74 hidden
int Android_JNI_SetClipboardText(const char *text)
GLint GLint GLint GLint z
int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames)
int SDL_SendAppEvent(SDL_EventType eventType)
DECLSPEC int SDLCALL SDL_SemPost(SDL_sem *sem)
int64_t Sint64
A signed 64-bit integer type.
#define EGL_RENDERABLE_TYPE
JNIEnv * Android_JNI_GetEnv(void)
int SDL_SendEditingText(const char *text, int start, int length)
Sint64 Android_JNI_FileSeek(SDL_RWops *ctx, Sint64 offset, int whence)
A rectangle, with the origin at the upper left.
GLint GLsizei const GLuint64 * values
void Android_JNI_SwapWindow()
#define EGL_OPENGL_ES2_BIT
Sint64 Android_JNI_FileSize(SDL_RWops *ctx)