Merged changes from Alexey Petruchik to support Android obb files http://developer.android.com/google/play/expansion-files.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
diff --git a/android-project/src/org/libsdl/app/SDLActivity.java b/android-project/src/org/libsdl/app/SDLActivity.java
index d759804..59d6a69 100644
--- a/android-project/src/org/libsdl/app/SDLActivity.java
+++ b/android-project/src/org/libsdl/app/SDLActivity.java
@@ -1,10 +1,13 @@
package org.libsdl.app;
+import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.lang.reflect.Method;
import android.app.*;
import android.content.*;
@@ -20,7 +23,6 @@ import android.graphics.*;
import android.media.*;
import android.hardware.*;
-
/**
SDL Activity
*/
@@ -296,6 +298,7 @@ public class SDLActivity extends Activity {
int is_accelerometer, int nbuttons,
int naxes, int nhats, int nballs);
public static native int nativeRemoveJoystick(int device_id);
+ public static native String nativeGetHint(String name);
/**
* This method is called by SDL using JNI.
@@ -531,7 +534,52 @@ public class SDLActivity extends Activity {
mJoystickHandler.pollInputDevices();
}
}
-
+
+ // APK extension files support
+
+ /** com.android.vending.expansion.zipfile.ZipResourceFile object or null. */
+ private Object expansionFile;
+
+ /** com.android.vending.expansion.zipfile.ZipResourceFile's getInputStream() or null. */
+ private Method expansionFileMethod;
+
+ public InputStream openAPKExtensionInputStream(String fileName) throws IOException {
+ // Get a ZipResourceFile representing a merger of both the main and patch files
+ if (expansionFile == null) {
+ Integer mainVersion = Integer.parseInt(nativeGetHint("SDL_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION"));
+ Integer patchVersion = Integer.parseInt(nativeGetHint("SDL_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION"));
+
+ try {
+ // To avoid direct dependency on Google APK extension library that is
+ // not a part of Android SDK we access it using reflection
+ expansionFile = Class.forName("com.android.vending.expansion.zipfile.APKExpansionSupport")
+ .getMethod("getAPKExpansionZipFile", Context.class, int.class, int.class)
+ .invoke(null, this, mainVersion, patchVersion);
+
+ expansionFileMethod = expansionFile.getClass()
+ .getMethod("getInputStream", String.class);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ expansionFile = null;
+ expansionFileMethod = null;
+ }
+ }
+
+ // Get an input stream for a known file inside the expansion file ZIPs
+ InputStream fileStream;
+ try {
+ fileStream = (InputStream)expansionFileMethod.invoke(expansionFile, fileName);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ fileStream = null;
+ }
+
+ if (fileStream == null) {
+ throw new IOException();
+ }
+
+ return fileStream;
+ }
}
/**
diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index 249f24d..29d2b05 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -457,6 +457,16 @@ extern "C" {
*/
#define SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES "SDL_VIDEO_MAC_FULLSCREEN_SPACES"
+/**
+ * \brief Android APK expansion main file version. Should be a string number like "1", "2" etc.
+ */
+#define SDL_HINT_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION "SDL_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION"
+
+/**
+ * \brief Android APK expansion patch file version. Should be a string number like "1", "2" etc.
+ */
+#define SDL_HINT_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION "SDL_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION"
+
/**
* \brief An enumeration of hint priorities
diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c
index 3b18d17..096770d 100644
--- a/src/core/android/SDL_android.c
+++ b/src/core/android/SDL_android.c
@@ -385,7 +385,15 @@ JNIEXPORT void JNICALL Java_org_libsdl_app_SDLInputConnection_nativeSetComposing
(*env)->ReleaseStringUTFChars(env, text, utftext);
}
+jstring Java_org_libsdl_app_SDLActivity_nativeGetHint(JNIEnv* env, jclass cls, jstring name) {
+ const char *utfname = (*env)->GetStringUTFChars(env, name, NULL);
+ const char *hint = SDL_GetHint(utfname);
+ jstring result = (*env)->NewStringUTF(env, hint);
+ (*env)->ReleaseStringUTFChars(env, name, utfname);
+
+ return result;
+}
/*******************************************************************************
Functions called by SDL into Java
@@ -758,7 +766,14 @@ fallback:
"open", "(Ljava/lang/String;I)Ljava/io/InputStream;");
inputStream = (*mEnv)->CallObjectMethod(mEnv, assetManager, mid, fileNameJString, 1 /* ACCESS_RANDOM */);
if (Android_JNI_ExceptionOccurred(false)) {
- goto failure;
+ // Try fallback to APK Extension files
+ mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, context),
+ "openAPKExtensionInputStream", "(Ljava/lang/String;)Ljava/io/InputStream;");
+ inputStream = (*mEnv)->CallObjectMethod(mEnv, context, mid, fileNameJString);
+
+ if (Android_JNI_ExceptionOccurred(false)) {
+ goto failure;
+ }
}
ctx->hidden.androidio.inputStreamRef = (*mEnv)->NewGlobalRef(mEnv, inputStream);