mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-10-01 07:28:30 +00:00
Android: Allow SDL_IOFromFile to open content:// URI. (#9696)
This commit is contained in:
1
android-project/app/proguard-rules.pro
vendored
1
android-project/app/proguard-rules.pro
vendored
@@ -48,6 +48,7 @@
|
|||||||
int openURL(java.lang.String);
|
int openURL(java.lang.String);
|
||||||
int showToast(java.lang.String, int, int, int, int);
|
int showToast(java.lang.String, int, int, int, int);
|
||||||
native java.lang.String nativeGetHint(java.lang.String);
|
native java.lang.String nativeGetHint(java.lang.String);
|
||||||
|
int openFileDescriptor(java.lang.String, java.lang.String);
|
||||||
}
|
}
|
||||||
|
|
||||||
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.HIDDeviceManager {
|
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.HIDDeviceManager {
|
||||||
|
@@ -23,6 +23,7 @@ import android.os.Build;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
@@ -44,6 +45,7 @@ import android.widget.RelativeLayout;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@@ -1938,6 +1940,23 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called by SDL using JNI.
|
||||||
|
*/
|
||||||
|
public static int openFileDescriptor(String uri, String mode) throws Exception {
|
||||||
|
if (mSingleton == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ParcelFileDescriptor pfd = mSingleton.getContentResolver().openFileDescriptor(Uri.parse(uri), mode);
|
||||||
|
return pfd != null ? pfd.detachFd() : -1;
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -175,8 +175,9 @@ typedef struct SDL_IOStream SDL_IOStream;
|
|||||||
* This function supports Unicode filenames, but they must be encoded in UTF-8
|
* This function supports Unicode filenames, but they must be encoded in UTF-8
|
||||||
* format, regardless of the underlying operating system.
|
* format, regardless of the underlying operating system.
|
||||||
*
|
*
|
||||||
* As a fallback, SDL_IOFromFile() will transparently open a matching filename
|
* In Android, SDL_IOFromFile() can be used to open content:// URIs. As a
|
||||||
* in an Android app's `assets`.
|
* fallback, SDL_IOFromFile() will transparently open a matching filename
|
||||||
|
* in the app's `assets`.
|
||||||
*
|
*
|
||||||
* Closing the SDL_IOStream will close SDL's internal file handle.
|
* Closing the SDL_IOStream will close SDL's internal file handle.
|
||||||
*
|
*
|
||||||
|
@@ -345,6 +345,7 @@ static jmethodID midSetWindowStyle;
|
|||||||
static jmethodID midShouldMinimizeOnFocusLoss;
|
static jmethodID midShouldMinimizeOnFocusLoss;
|
||||||
static jmethodID midShowTextInput;
|
static jmethodID midShowTextInput;
|
||||||
static jmethodID midSupportsRelativeMouse;
|
static jmethodID midSupportsRelativeMouse;
|
||||||
|
static jmethodID midOpenFileDescriptor;
|
||||||
|
|
||||||
/* audio manager */
|
/* audio manager */
|
||||||
static jclass mAudioManagerClass;
|
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");
|
midShouldMinimizeOnFocusLoss = (*env)->GetStaticMethodID(env, mActivityClass, "shouldMinimizeOnFocusLoss", "()Z");
|
||||||
midShowTextInput = (*env)->GetStaticMethodID(env, mActivityClass, "showTextInput", "(IIII)Z");
|
midShowTextInput = (*env)->GetStaticMethodID(env, mActivityClass, "showTextInput", "(IIII)Z");
|
||||||
midSupportsRelativeMouse = (*env)->GetStaticMethodID(env, mActivityClass, "supportsRelativeMouse", "()Z");
|
midSupportsRelativeMouse = (*env)->GetStaticMethodID(env, mActivityClass, "supportsRelativeMouse", "()Z");
|
||||||
|
midOpenFileDescriptor = (*env)->GetStaticMethodID(env, mActivityClass, "openFileDescriptor", "(Ljava/lang/String;Ljava/lang/String;)I");
|
||||||
|
|
||||||
if (!midClipboardGetText ||
|
if (!midClipboardGetText ||
|
||||||
!midClipboardHasText ||
|
!midClipboardHasText ||
|
||||||
@@ -667,7 +669,8 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
|
|||||||
!midSetWindowStyle ||
|
!midSetWindowStyle ||
|
||||||
!midShouldMinimizeOnFocusLoss ||
|
!midShouldMinimizeOnFocusLoss ||
|
||||||
!midShowTextInput ||
|
!midShowTextInput ||
|
||||||
!midSupportsRelativeMouse) {
|
!midSupportsRelativeMouse ||
|
||||||
|
!midOpenFileDescriptor) {
|
||||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLActivity.java?");
|
__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;
|
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 */
|
#endif /* SDL_PLATFORM_ANDROID */
|
||||||
|
@@ -75,6 +75,7 @@ int Android_JNI_FileClose(void *userdata);
|
|||||||
|
|
||||||
/* Environment support */
|
/* Environment support */
|
||||||
void Android_JNI_GetManifestEnvironmentVariables(void);
|
void Android_JNI_GetManifestEnvironmentVariables(void);
|
||||||
|
int Android_JNI_OpenFileDescriptor(const char *uri, const char *mode);
|
||||||
|
|
||||||
/* Clipboard support */
|
/* Clipboard support */
|
||||||
int Android_JNI_SetClipboardText(const char *text);
|
int Android_JNI_SetClipboardText(const char *text);
|
||||||
|
@@ -54,6 +54,7 @@ struct SDL_IOStream
|
|||||||
#endif /* SDL_PLATFORM_3DS */
|
#endif /* SDL_PLATFORM_3DS */
|
||||||
|
|
||||||
#ifdef SDL_PLATFORM_ANDROID
|
#ifdef SDL_PLATFORM_ANDROID
|
||||||
|
#include <unistd.h>
|
||||||
#include "../core/android/SDL_android.h"
|
#include "../core/android/SDL_android.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -558,6 +559,22 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
|
|||||||
}
|
}
|
||||||
return SDL_IOFromFP(fp, 1);
|
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 {
|
} else {
|
||||||
/* Try opening it from internal storage if it's a relative path */
|
/* Try opening it from internal storage if it's a relative path */
|
||||||
// !!! FIXME: why not just "char path[PATH_MAX];"
|
// !!! FIXME: why not just "char path[PATH_MAX];"
|
||||||
|
Reference in New Issue
Block a user