Last active
June 21, 2016 09:10
-
-
Save seven332/10e48beb8d667cb5cbf4b401216d9203 to your computer and use it in GitHub Desktop.
Base on SDL release-2.0.4
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: include/SDL_rwops.h | |
=================================================================== | |
--- include/SDL_rwops.h (revision 8be6e5ca9041dfcf8b20c85e43eb3beaa6efdd2b) | |
+++ include/SDL_rwops.h (revision ) | |
@@ -96,15 +96,7 @@ | |
#if defined(__ANDROID__) | |
struct | |
{ | |
- void *fileNameRef; | |
- void *inputStreamRef; | |
- void *readableByteChannelRef; | |
- void *readMethod; | |
- void *assetFileDescriptorRef; | |
- long position; | |
- long size; | |
- long offset; | |
- int fd; | |
+ void *asset; | |
} androidio; | |
#elif defined(__WIN32__) | |
struct | |
Index: src/core/android/SDL_android.c | |
=================================================================== | |
--- src/core/android/SDL_android.c (revision 8be6e5ca9041dfcf8b20c85e43eb3beaa6efdd2b) | |
+++ src/core/android/SDL_android.c (revision ) | |
@@ -38,6 +38,7 @@ | |
#include "../../video/android/SDL_androidwindow.h" | |
#include "../../joystick/android/SDL_sysjoystick_c.h" | |
+#include <android/asset_manager_jni.h> | |
#include <android/log.h> | |
#include <pthread.h> | |
#include <sys/types.h> | |
@@ -77,6 +78,9 @@ | |
static jmethodID midAudioQuit; | |
static jmethodID midPollInputDevices; | |
+/* AAssetManager */ | |
+static AAssetManager *mAssetManager; | |
+ | |
/* Accelerometer data storage */ | |
static float fLastAccelerometer[3]; | |
static SDL_bool bHasNewData; | |
@@ -110,6 +114,10 @@ | |
/* Called before SDL_main() to initialize JNI bindings */ | |
JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv* mEnv, jclass cls) | |
{ | |
+ jmethodID mid; | |
+ jobject context; | |
+ jobject assetManager; | |
+ | |
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init()"); | |
Android_JNI_SetupThread(); | |
@@ -129,6 +137,18 @@ | |
midPollInputDevices = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, | |
"pollInputDevices", "()V"); | |
+ /* context = SDLActivity.getContext(); */ | |
+ mid = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, | |
+ "getContext","()Landroid/content/Context;"); | |
+ context = (*mEnv)->CallStaticObjectMethod(mEnv, mActivityClass, mid); | |
+ | |
+ /* assetManager = context.getAssets(); */ | |
+ mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, context), | |
+ "getAssets", "()Landroid/content/res/AssetManager;"); | |
+ assetManager = (*mEnv)->CallObjectMethod(mEnv, context, mid); | |
+ | |
+ mAssetManager = AAssetManager_fromJava(mEnv, assetManager); | |
+ | |
bHasNewData = SDL_FALSE; | |
if (!midGetNativeSurface || !midAudioInit || | |
@@ -691,251 +711,27 @@ | |
return SDL_FALSE; | |
} | |
-static int Internal_Android_JNI_FileOpen(SDL_RWops* ctx) | |
-{ | |
- struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); | |
- | |
- int result = 0; | |
- | |
- jmethodID mid; | |
- jobject context; | |
- jobject assetManager; | |
- jobject inputStream; | |
- jclass channels; | |
- jobject readableByteChannel; | |
- jstring fileNameJString; | |
- jobject fd; | |
- jclass fdCls; | |
- jfieldID descriptor; | |
- | |
- JNIEnv *mEnv = Android_JNI_GetEnv(); | |
- if (!LocalReferenceHolder_Init(&refs, mEnv)) { | |
- goto failure; | |
- } | |
- | |
- fileNameJString = (jstring)ctx->hidden.androidio.fileNameRef; | |
- ctx->hidden.androidio.position = 0; | |
- | |
- /* context = SDLActivity.getContext(); */ | |
- mid = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, | |
- "getContext","()Landroid/content/Context;"); | |
- context = (*mEnv)->CallStaticObjectMethod(mEnv, mActivityClass, mid); | |
- | |
- | |
- /* assetManager = context.getAssets(); */ | |
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, context), | |
- "getAssets", "()Landroid/content/res/AssetManager;"); | |
- assetManager = (*mEnv)->CallObjectMethod(mEnv, context, mid); | |
- | |
- /* First let's try opening the file to obtain an AssetFileDescriptor. | |
- * This method reads the files directly from the APKs using standard *nix calls | |
- */ | |
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, assetManager), "openFd", "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;"); | |
- inputStream = (*mEnv)->CallObjectMethod(mEnv, assetManager, mid, fileNameJString); | |
- if (Android_JNI_ExceptionOccurred(SDL_TRUE)) { | |
- goto fallback; | |
- } | |
- | |
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream), "getStartOffset", "()J"); | |
- ctx->hidden.androidio.offset = (*mEnv)->CallLongMethod(mEnv, inputStream, mid); | |
- if (Android_JNI_ExceptionOccurred(SDL_TRUE)) { | |
- goto fallback; | |
- } | |
- | |
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream), "getDeclaredLength", "()J"); | |
- ctx->hidden.androidio.size = (*mEnv)->CallLongMethod(mEnv, inputStream, mid); | |
- if (Android_JNI_ExceptionOccurred(SDL_TRUE)) { | |
- goto fallback; | |
- } | |
- | |
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream), "getFileDescriptor", "()Ljava/io/FileDescriptor;"); | |
- fd = (*mEnv)->CallObjectMethod(mEnv, inputStream, mid); | |
- fdCls = (*mEnv)->GetObjectClass(mEnv, fd); | |
- descriptor = (*mEnv)->GetFieldID(mEnv, fdCls, "descriptor", "I"); | |
- ctx->hidden.androidio.fd = (*mEnv)->GetIntField(mEnv, fd, descriptor); | |
- ctx->hidden.androidio.assetFileDescriptorRef = (*mEnv)->NewGlobalRef(mEnv, inputStream); | |
- | |
- /* Seek to the correct offset in the file. */ | |
- lseek(ctx->hidden.androidio.fd, (off_t)ctx->hidden.androidio.offset, SEEK_SET); | |
- | |
- if (0) { | |
-fallback: | |
- /* Disabled log message because of spam on the Nexus 7 */ | |
- /* __android_log_print(ANDROID_LOG_DEBUG, "SDL", "Falling back to legacy InputStream method for opening file"); */ | |
- | |
- /* Try the old method using InputStream */ | |
- ctx->hidden.androidio.assetFileDescriptorRef = NULL; | |
- | |
- /* inputStream = assetManager.open(<filename>); */ | |
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, assetManager), | |
- "open", "(Ljava/lang/String;I)Ljava/io/InputStream;"); | |
- inputStream = (*mEnv)->CallObjectMethod(mEnv, assetManager, mid, fileNameJString, 1 /* ACCESS_RANDOM */); | |
- if (Android_JNI_ExceptionOccurred(SDL_FALSE)) { | |
- /* Try fallback to APK expansion files */ | |
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, context), | |
- "openAPKExpansionInputStream", "(Ljava/lang/String;)Ljava/io/InputStream;"); | |
- if (!mid) { | |
- SDL_SetError("No openAPKExpansionInputStream() in Java class"); | |
- goto failure; /* Java class is missing the required method */ | |
- } | |
- inputStream = (*mEnv)->CallObjectMethod(mEnv, context, mid, fileNameJString); | |
- | |
- /* Exception is checked first because it always needs to be cleared. | |
- * If no exception occurred then the last SDL error message is kept. | |
- */ | |
- if (Android_JNI_ExceptionOccurred(SDL_FALSE) || !inputStream) { | |
- goto failure; | |
- } | |
- } | |
- | |
- ctx->hidden.androidio.inputStreamRef = (*mEnv)->NewGlobalRef(mEnv, inputStream); | |
- | |
- /* Despite all the visible documentation on [Asset]InputStream claiming | |
- * that the .available() method is not guaranteed to return the entire file | |
- * size, comments in <sdk>/samples/<ver>/ApiDemos/src/com/example/ ... | |
- * android/apis/content/ReadAsset.java imply that Android's | |
- * AssetInputStream.available() /will/ always return the total file size | |
- */ | |
- | |
- /* size = inputStream.available(); */ | |
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream), | |
- "available", "()I"); | |
- ctx->hidden.androidio.size = (long)(*mEnv)->CallIntMethod(mEnv, inputStream, mid); | |
- if (Android_JNI_ExceptionOccurred(SDL_FALSE)) { | |
- goto failure; | |
- } | |
- | |
- /* readableByteChannel = Channels.newChannel(inputStream); */ | |
- channels = (*mEnv)->FindClass(mEnv, "java/nio/channels/Channels"); | |
- mid = (*mEnv)->GetStaticMethodID(mEnv, channels, | |
- "newChannel", | |
- "(Ljava/io/InputStream;)Ljava/nio/channels/ReadableByteChannel;"); | |
- readableByteChannel = (*mEnv)->CallStaticObjectMethod( | |
- mEnv, channels, mid, inputStream); | |
- if (Android_JNI_ExceptionOccurred(SDL_FALSE)) { | |
- goto failure; | |
- } | |
- | |
- ctx->hidden.androidio.readableByteChannelRef = | |
- (*mEnv)->NewGlobalRef(mEnv, readableByteChannel); | |
- | |
- /* Store .read id for reading purposes */ | |
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, readableByteChannel), | |
- "read", "(Ljava/nio/ByteBuffer;)I"); | |
- ctx->hidden.androidio.readMethod = mid; | |
- } | |
- | |
- if (0) { | |
-failure: | |
- result = -1; | |
- | |
- (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.fileNameRef); | |
- | |
- if(ctx->hidden.androidio.inputStreamRef != NULL) { | |
- (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.inputStreamRef); | |
- } | |
- | |
- if(ctx->hidden.androidio.readableByteChannelRef != NULL) { | |
- (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.readableByteChannelRef); | |
- } | |
- | |
- if(ctx->hidden.androidio.assetFileDescriptorRef != NULL) { | |
- (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.assetFileDescriptorRef); | |
- } | |
- | |
- } | |
- | |
- LocalReferenceHolder_Cleanup(&refs); | |
- return result; | |
-} | |
- | |
int Android_JNI_FileOpen(SDL_RWops* ctx, | |
const char* fileName, const char* mode) | |
{ | |
- struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); | |
- JNIEnv *mEnv = Android_JNI_GetEnv(); | |
- int retval; | |
- | |
- if (!LocalReferenceHolder_Init(&refs, mEnv)) { | |
- LocalReferenceHolder_Cleanup(&refs); | |
+ AAsset *asset = AAssetManager_open(mAssetManager, fileName, AASSET_MODE_BUFFER); | |
+ if (asset == NULL) { | |
return -1; | |
} | |
- | |
- if (!ctx) { | |
- LocalReferenceHolder_Cleanup(&refs); | |
- return -1; | |
+ ctx->hidden.androidio.asset = asset; | |
+ return 0; | |
- } | |
+} | |
- jstring fileNameJString = (*mEnv)->NewStringUTF(mEnv, fileName); | |
- ctx->hidden.androidio.fileNameRef = (*mEnv)->NewGlobalRef(mEnv, fileNameJString); | |
- ctx->hidden.androidio.inputStreamRef = NULL; | |
- ctx->hidden.androidio.readableByteChannelRef = NULL; | |
- ctx->hidden.androidio.readMethod = NULL; | |
- ctx->hidden.androidio.assetFileDescriptorRef = NULL; | |
- | |
- retval = Internal_Android_JNI_FileOpen(ctx); | |
- LocalReferenceHolder_Cleanup(&refs); | |
- return retval; | |
-} | |
- | |
size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer, | |
size_t size, size_t maxnum) | |
{ | |
- struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); | |
- | |
- if (ctx->hidden.androidio.assetFileDescriptorRef) { | |
- size_t bytesMax = size * maxnum; | |
- if (ctx->hidden.androidio.size != -1 /* UNKNOWN_LENGTH */ && ctx->hidden.androidio.position + bytesMax > ctx->hidden.androidio.size) { | |
- bytesMax = ctx->hidden.androidio.size - ctx->hidden.androidio.position; | |
- } | |
- size_t result = read(ctx->hidden.androidio.fd, buffer, bytesMax ); | |
- if (result > 0) { | |
- ctx->hidden.androidio.position += result; | |
- LocalReferenceHolder_Cleanup(&refs); | |
- return result / size; | |
- } | |
- LocalReferenceHolder_Cleanup(&refs); | |
+ if (ctx->hidden.androidio.asset == NULL) { | |
return 0; | |
} else { | |
- jlong bytesRemaining = (jlong) (size * maxnum); | |
- jlong bytesMax = (jlong) (ctx->hidden.androidio.size - ctx->hidden.androidio.position); | |
- int bytesRead = 0; | |
- | |
- /* Don't read more bytes than those that remain in the file, otherwise we get an exception */ | |
- if (bytesRemaining > bytesMax) bytesRemaining = bytesMax; | |
- | |
- JNIEnv *mEnv = Android_JNI_GetEnv(); | |
- if (!LocalReferenceHolder_Init(&refs, mEnv)) { | |
- LocalReferenceHolder_Cleanup(&refs); | |
- return 0; | |
+ return AAsset_read((AAsset *)ctx->hidden.androidio.asset, buffer, size * maxnum) / size; | |
- } | |
+ } | |
- | |
- jobject readableByteChannel = (jobject)ctx->hidden.androidio.readableByteChannelRef; | |
- jmethodID readMethod = (jmethodID)ctx->hidden.androidio.readMethod; | |
- jobject byteBuffer = (*mEnv)->NewDirectByteBuffer(mEnv, buffer, bytesRemaining); | |
- | |
- while (bytesRemaining > 0) { | |
- /* result = readableByteChannel.read(...); */ | |
- int result = (*mEnv)->CallIntMethod(mEnv, readableByteChannel, readMethod, byteBuffer); | |
- | |
- if (Android_JNI_ExceptionOccurred(SDL_FALSE)) { | |
- LocalReferenceHolder_Cleanup(&refs); | |
- return 0; | |
- } | |
+} | |
- if (result < 0) { | |
- break; | |
- } | |
- | |
- bytesRemaining -= result; | |
- bytesRead += result; | |
- ctx->hidden.androidio.position += result; | |
- } | |
- LocalReferenceHolder_Cleanup(&refs); | |
- return bytesRead / size; | |
- } | |
-} | |
- | |
size_t Android_JNI_FileWrite(SDL_RWops* ctx, const void* buffer, | |
size_t size, size_t num) | |
{ | |
@@ -943,146 +739,20 @@ | |
return 0; | |
} | |
-static int Internal_Android_JNI_FileClose(SDL_RWops* ctx, SDL_bool release) | |
-{ | |
- struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); | |
- | |
- int result = 0; | |
- JNIEnv *mEnv = Android_JNI_GetEnv(); | |
- | |
- if (!LocalReferenceHolder_Init(&refs, mEnv)) { | |
- LocalReferenceHolder_Cleanup(&refs); | |
- return SDL_SetError("Failed to allocate enough JVM local references"); | |
- } | |
- | |
- if (ctx) { | |
- if (release) { | |
- (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.fileNameRef); | |
- } | |
- | |
- if (ctx->hidden.androidio.assetFileDescriptorRef) { | |
- jobject inputStream = (jobject)ctx->hidden.androidio.assetFileDescriptorRef; | |
- jmethodID mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream), | |
- "close", "()V"); | |
- (*mEnv)->CallVoidMethod(mEnv, inputStream, mid); | |
- (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.assetFileDescriptorRef); | |
- if (Android_JNI_ExceptionOccurred(SDL_FALSE)) { | |
- result = -1; | |
- } | |
- } | |
- else { | |
- jobject inputStream = (jobject)ctx->hidden.androidio.inputStreamRef; | |
- | |
- /* inputStream.close(); */ | |
- jmethodID mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream), | |
- "close", "()V"); | |
- (*mEnv)->CallVoidMethod(mEnv, inputStream, mid); | |
- (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.inputStreamRef); | |
- (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.readableByteChannelRef); | |
- if (Android_JNI_ExceptionOccurred(SDL_FALSE)) { | |
- result = -1; | |
- } | |
- } | |
- | |
- if (release) { | |
- SDL_FreeRW(ctx); | |
- } | |
- } | |
- | |
- LocalReferenceHolder_Cleanup(&refs); | |
- return result; | |
-} | |
- | |
- | |
Sint64 Android_JNI_FileSize(SDL_RWops* ctx) | |
{ | |
- return ctx->hidden.androidio.size; | |
+ return AAsset_getLength((AAsset *) ctx->hidden.androidio.asset); | |
} | |
Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence) | |
{ | |
- if (ctx->hidden.androidio.assetFileDescriptorRef) { | |
- switch (whence) { | |
- case RW_SEEK_SET: | |
- if (ctx->hidden.androidio.size != -1 /* UNKNOWN_LENGTH */ && offset > ctx->hidden.androidio.size) offset = ctx->hidden.androidio.size; | |
- offset += ctx->hidden.androidio.offset; | |
- break; | |
- case RW_SEEK_CUR: | |
- offset += ctx->hidden.androidio.position; | |
- if (ctx->hidden.androidio.size != -1 /* UNKNOWN_LENGTH */ && offset > ctx->hidden.androidio.size) offset = ctx->hidden.androidio.size; | |
- offset += ctx->hidden.androidio.offset; | |
- break; | |
- case RW_SEEK_END: | |
- offset = ctx->hidden.androidio.offset + ctx->hidden.androidio.size + offset; | |
- break; | |
- default: | |
- return SDL_SetError("Unknown value for 'whence'"); | |
+ return AAsset_seek((AAsset *) ctx->hidden.androidio.asset, offset, whence); | |
- } | |
+} | |
- whence = SEEK_SET; | |
- off_t ret = lseek(ctx->hidden.androidio.fd, (off_t)offset, SEEK_SET); | |
- if (ret == -1) return -1; | |
- ctx->hidden.androidio.position = ret - ctx->hidden.androidio.offset; | |
- } else { | |
- Sint64 newPosition; | |
- | |
- switch (whence) { | |
- case RW_SEEK_SET: | |
- newPosition = offset; | |
- break; | |
- case RW_SEEK_CUR: | |
- newPosition = ctx->hidden.androidio.position + offset; | |
- break; | |
- case RW_SEEK_END: | |
- newPosition = ctx->hidden.androidio.size + offset; | |
- break; | |
- default: | |
- return SDL_SetError("Unknown value for 'whence'"); | |
- } | |
- | |
- /* Validate the new position */ | |
- if (newPosition < 0) { | |
- return SDL_Error(SDL_EFSEEK); | |
- } | |
- if (newPosition > ctx->hidden.androidio.size) { | |
- newPosition = ctx->hidden.androidio.size; | |
- } | |
- | |
- Sint64 movement = newPosition - ctx->hidden.androidio.position; | |
- if (movement > 0) { | |
- unsigned char buffer[4096]; | |
- | |
- /* The easy case where we're seeking forwards */ | |
- while (movement > 0) { | |
- Sint64 amount = sizeof (buffer); | |
- if (amount > movement) { | |
- amount = movement; | |
- } | |
- size_t result = Android_JNI_FileRead(ctx, buffer, 1, amount); | |
- if (result <= 0) { | |
- /* Failed to read/skip the required amount, so fail */ | |
- return -1; | |
- } | |
- | |
- movement -= result; | |
- } | |
- | |
- } else if (movement < 0) { | |
- /* We can't seek backwards so we have to reopen the file and seek */ | |
- /* forwards which obviously isn't very efficient */ | |
- Internal_Android_JNI_FileClose(ctx, SDL_FALSE); | |
- Internal_Android_JNI_FileOpen(ctx); | |
- Android_JNI_FileSeek(ctx, newPosition, RW_SEEK_SET); | |
- } | |
- } | |
- | |
- return ctx->hidden.androidio.position; | |
- | |
-} | |
- | |
int Android_JNI_FileClose(SDL_RWops* ctx) | |
{ | |
- return Internal_Android_JNI_FileClose(ctx, SDL_TRUE); | |
+ AAsset_close((AAsset *) ctx->hidden.androidio.asset); | |
+ return (int) NULL; | |
} | |
/* returns a new global reference which needs to be released later */ | |
@@ -1621,4 +1291,3 @@ | |
#endif /* __ANDROID__ */ | |
/* vi: set ts=4 sw=4 expandtab: */ | |
- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment