Android: Allow SDL_IOFromFile to open content:// URI. (#9696)

This commit is contained in:
Miku AuahDark 2024-05-07 00:05:49 +08:00 committed by GitHub
parent 61c99c0da7
commit 33ae7e38d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 99 additions and 3 deletions

View file

@ -345,6 +345,7 @@ static jmethodID midSetWindowStyle;
static jmethodID midShouldMinimizeOnFocusLoss;
static jmethodID midShowTextInput;
static jmethodID midSupportsRelativeMouse;
static jmethodID midOpenFileDescriptor;
/* audio manager */
static jclass mAudioManagerClass;
@ -638,6 +639,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
midShouldMinimizeOnFocusLoss = (*env)->GetStaticMethodID(env, mActivityClass, "shouldMinimizeOnFocusLoss", "()Z");
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");
if (!midClipboardGetText ||
!midClipboardHasText ||
@ -667,7 +669,8 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
!midSetWindowStyle ||
!midShouldMinimizeOnFocusLoss ||
!midShowTextInput ||
!midSupportsRelativeMouse) {
!midSupportsRelativeMouse ||
!midOpenFileDescriptor) {
__android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLActivity.java?");
}
@ -2766,4 +2769,58 @@ int Android_JNI_OpenURL(const char *url)
return ret;
}
int Android_JNI_OpenFileDescriptor(const char *uri, const char *mode)
{
/* Get fopen-style modes */
int moderead = 0, modewrite = 0, modeappend = 0, modeupdate = 0;
for (const char *cmode = mode; *cmode; cmode++) {
switch (*cmode) {
case 'a':
modeappend = 1;
break;
case 'r':
moderead = 1;
break;
case 'w':
modewrite = 1;
break;
case '+':
modeupdate = 1;
break;
default:
break;
}
}
/* Translate fopen-style modes to ContentResolver modes. */
/* Android only allows "r", "w", "wt", "wa", "rw" or "rwt". */
const char *contentResolverMode = "r";
if (moderead) {
if (modewrite) {
contentResolverMode = "rwt";
} else {
contentResolverMode = modeupdate ? "rw" : "r";
}
} else if (modewrite) {
contentResolverMode = modeupdate ? "rwt" : "wt";
} else if (modeappend) {
contentResolverMode = modeupdate ? "rw" : "wa";
}
JNIEnv *env = Android_JNI_GetEnv();
jstring jstringUri = (*env)->NewStringUTF(env, uri);
jstring jstringMode = (*env)->NewStringUTF(env, contentResolverMode);
jint fd = (*env)->CallStaticIntMethod(env, mActivityClass, midOpenFileDescriptor, jstringUri, jstringMode);
(*env)->DeleteLocalRef(env, jstringUri);
(*env)->DeleteLocalRef(env, jstringMode);
if (fd == -1) {
SDL_SetError("Unspecified error in JNI");
}
return fd;
}
#endif /* SDL_PLATFORM_ANDROID */

View file

@ -75,6 +75,7 @@ int Android_JNI_FileClose(void *userdata);
/* Environment support */
void Android_JNI_GetManifestEnvironmentVariables(void);
int Android_JNI_OpenFileDescriptor(const char *uri, const char *mode);
/* Clipboard support */
int Android_JNI_SetClipboardText(const char *text);

View file

@ -54,6 +54,7 @@ struct SDL_IOStream
#endif /* SDL_PLATFORM_3DS */
#ifdef SDL_PLATFORM_ANDROID
#include <unistd.h>
#include "../core/android/SDL_android.h"
#endif
@ -558,6 +559,22 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
}
return SDL_IOFromFP(fp, 1);
}
} else if (SDL_strncmp(file, "content://", 10) == 0) {
/* Try opening content:// URI */
int fd = Android_JNI_OpenFileDescriptor(file, mode);
if (fd == -1) {
/* SDL error is already set. */
return NULL;
}
FILE *fp = fdopen(fd, mode);
if (!fp) {
close(fd);
SDL_SetError("Unable to open file descriptor (%d) from URI %s", fd, file);
return NULL;
}
return SDL_IOFromFP(fp, SDL_TRUE);
} else {
/* Try opening it from internal storage if it's a relative path */
// !!! FIXME: why not just "char path[PATH_MAX];"