mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-05-27 23:19:11 +00:00
Android: Implement open and save file dialog.
This commit is contained in:
parent
ea1904eda1
commit
86fada6faa
7 changed files with 312 additions and 3 deletions
|
@ -177,6 +177,10 @@ JNIEXPORT jboolean JNICALL SDL_JAVA_INTERFACE(nativeAllowRecreateActivity)(
|
|||
JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeCheckSDLThreadCounter)(
|
||||
JNIEnv *env, jclass jcls);
|
||||
|
||||
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeFileDialog)(
|
||||
JNIEnv *env, jclass jcls,
|
||||
jint requestCode, jobjectArray fileList, jint filter);
|
||||
|
||||
static JNINativeMethod SDLActivity_tab[] = {
|
||||
{ "nativeGetVersion", "()Ljava/lang/String;", SDL_JAVA_INTERFACE(nativeGetVersion) },
|
||||
{ "nativeSetupJNI", "()I", SDL_JAVA_INTERFACE(nativeSetupJNI) },
|
||||
|
@ -211,7 +215,8 @@ static JNINativeMethod SDLActivity_tab[] = {
|
|||
{ "nativeAddTouch", "(ILjava/lang/String;)V", SDL_JAVA_INTERFACE(nativeAddTouch) },
|
||||
{ "nativePermissionResult", "(IZ)V", SDL_JAVA_INTERFACE(nativePermissionResult) },
|
||||
{ "nativeAllowRecreateActivity", "()Z", SDL_JAVA_INTERFACE(nativeAllowRecreateActivity) },
|
||||
{ "nativeCheckSDLThreadCounter", "()I", SDL_JAVA_INTERFACE(nativeCheckSDLThreadCounter) }
|
||||
{ "nativeCheckSDLThreadCounter", "()I", SDL_JAVA_INTERFACE(nativeCheckSDLThreadCounter) },
|
||||
{ "onNativeFileDialog", "(I[Ljava/lang/String;I)V", SDL_JAVA_INTERFACE(onNativeFileDialog) }
|
||||
};
|
||||
|
||||
/* Java class SDLInputConnection */
|
||||
|
@ -346,6 +351,7 @@ static jmethodID midShouldMinimizeOnFocusLoss;
|
|||
static jmethodID midShowTextInput;
|
||||
static jmethodID midSupportsRelativeMouse;
|
||||
static jmethodID midOpenFileDescriptor;
|
||||
static jmethodID midShowFileDialog;
|
||||
|
||||
/* audio manager */
|
||||
static jclass mAudioManagerClass;
|
||||
|
@ -640,6 +646,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
|
|||
midShowTextInput = (*env)->GetStaticMethodID(env, mActivityClass, "showTextInput", "(IIII)Z");
|
||||
midSupportsRelativeMouse = (*env)->GetStaticMethodID(env, mActivityClass, "supportsRelativeMouse", "()Z");
|
||||
midOpenFileDescriptor = (*env)->GetStaticMethodID(env, mActivityClass, "openFileDescriptor", "(Ljava/lang/String;Ljava/lang/String;)I");
|
||||
midShowFileDialog = (*env)->GetStaticMethodID(env, mActivityClass, "showFileDialog", "([Ljava/lang/String;ZZI)Z");
|
||||
|
||||
if (!midClipboardGetText ||
|
||||
!midClipboardHasText ||
|
||||
|
@ -670,7 +677,8 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
|
|||
!midShouldMinimizeOnFocusLoss ||
|
||||
!midShowTextInput ||
|
||||
!midSupportsRelativeMouse ||
|
||||
!midOpenFileDescriptor) {
|
||||
!midOpenFileDescriptor ||
|
||||
!midShowFileDialog) {
|
||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLActivity.java?");
|
||||
}
|
||||
|
||||
|
@ -2823,4 +2831,138 @@ int Android_JNI_OpenFileDescriptor(const char *uri, const char *mode)
|
|||
return fd;
|
||||
}
|
||||
|
||||
static struct AndroidFileDialog
|
||||
{
|
||||
int request_code;
|
||||
SDL_DialogFileCallback callback;
|
||||
void *userdata;
|
||||
} mAndroidFileDialogData;
|
||||
|
||||
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeFileDialog)(
|
||||
JNIEnv *env, jclass jcls,
|
||||
jint requestCode, jobjectArray fileList, jint filter)
|
||||
{
|
||||
if (mAndroidFileDialogData.callback != NULL && mAndroidFileDialogData.request_code == requestCode) {
|
||||
if (fileList == NULL) {
|
||||
SDL_SetError("Unspecified error in JNI");
|
||||
mAndroidFileDialogData.callback(mAndroidFileDialogData.userdata, NULL, -1);
|
||||
mAndroidFileDialogData.callback = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert fileList to string */
|
||||
size_t count = (*env)->GetArrayLength(env, fileList);
|
||||
char **charFileList = SDL_calloc(sizeof(char*), count + 1);
|
||||
|
||||
if (charFileList == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
mAndroidFileDialogData.callback(mAndroidFileDialogData.userdata, NULL, -1);
|
||||
mAndroidFileDialogData.callback = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert to UTF-8 */
|
||||
/* TODO: Fix modified UTF-8 to classic UTF-8 */
|
||||
for (int i = 0; i < count; i++) {
|
||||
jstring string = (*env)->GetObjectArrayElement(env, fileList, i);
|
||||
if (!string) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *utf8string = (*env)->GetStringUTFChars(env, string, NULL);
|
||||
if (!utf8string) {
|
||||
(*env)->DeleteLocalRef(env, string);
|
||||
continue;
|
||||
}
|
||||
|
||||
char *newFile = SDL_strdup(utf8string);
|
||||
if (!newFile) {
|
||||
(*env)->ReleaseStringUTFChars(env, string, utf8string);
|
||||
(*env)->DeleteLocalRef(env, string);
|
||||
SDL_OutOfMemory();
|
||||
mAndroidFileDialogData.callback(mAndroidFileDialogData.userdata, NULL, -1);
|
||||
mAndroidFileDialogData.callback = NULL;
|
||||
|
||||
/* Cleanup memory */
|
||||
for (int j = 0; j < i; j++) {
|
||||
SDL_free(charFileList[j]);
|
||||
}
|
||||
SDL_free(charFileList);
|
||||
return;
|
||||
}
|
||||
|
||||
charFileList[i] = newFile;
|
||||
(*env)->ReleaseStringUTFChars(env, string, utf8string);
|
||||
(*env)->DeleteLocalRef(env, string);
|
||||
}
|
||||
|
||||
/* Call user-provided callback */
|
||||
SDL_ClearError();
|
||||
mAndroidFileDialogData.callback(mAndroidFileDialogData.userdata, (const char *const *) charFileList, filter);
|
||||
mAndroidFileDialogData.callback = NULL;
|
||||
|
||||
/* Cleanup memory */
|
||||
for (int i = 0; i < count; i++) {
|
||||
SDL_free(charFileList[i]);
|
||||
}
|
||||
SDL_free(charFileList);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_bool Android_JNI_OpenFileDialog(
|
||||
SDL_DialogFileCallback callback, void* userdata,
|
||||
const SDL_DialogFileFilter *filters, SDL_bool forwrite, SDL_bool multiple)
|
||||
{
|
||||
if (mAndroidFileDialogData.callback != NULL) {
|
||||
SDL_SetError("Only one file dialog can be run at a time.");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (forwrite) {
|
||||
multiple = SDL_FALSE;
|
||||
}
|
||||
|
||||
JNIEnv *env = Android_JNI_GetEnv();
|
||||
|
||||
/* Setup filters */
|
||||
jobjectArray filtersArray = NULL;
|
||||
if (filters) {
|
||||
/* Count how many filters */
|
||||
int count = 0;
|
||||
for (const SDL_DialogFileFilter *f = filters; f->name != NULL && f->pattern != NULL; f++) {
|
||||
count++;
|
||||
}
|
||||
|
||||
jclass stringClass = (*env)->FindClass(env, "java/lang/String");
|
||||
filtersArray = (*env)->NewObjectArray(env, count, stringClass, NULL);
|
||||
|
||||
/* Convert to string */
|
||||
for (int i = 0; i < count; i++) {
|
||||
jstring str = (*env)->NewStringUTF(env, filters[i].pattern);
|
||||
(*env)->SetObjectArrayElement(env, filtersArray, i, str);
|
||||
(*env)->DeleteLocalRef(env, str);
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup data */
|
||||
static SDL_AtomicInt next_request_code;
|
||||
mAndroidFileDialogData.request_code = SDL_AtomicAdd(&next_request_code, 1);
|
||||
mAndroidFileDialogData.userdata = userdata;
|
||||
mAndroidFileDialogData.callback = callback;
|
||||
|
||||
/* Invoke JNI */
|
||||
jboolean success = (*env)->CallStaticBooleanMethod(env, mActivityClass,
|
||||
midShowFileDialog, filtersArray, (jboolean) multiple, (jboolean) forwrite, mAndroidFileDialogData.request_code);
|
||||
(*env)->DeleteLocalRef(env, filtersArray);
|
||||
if (!success) {
|
||||
mAndroidFileDialogData.callback = NULL;
|
||||
SDL_AtomicAdd(&next_request_code, -1);
|
||||
SDL_SetError("Unspecified error in JNI");
|
||||
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
#endif /* SDL_PLATFORM_ANDROID */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue