1.1 --- a/android-project/src/org/libsdl/app/SDLActivity.java Sat Jun 21 17:31:36 2014 -0700
1.2 +++ b/android-project/src/org/libsdl/app/SDLActivity.java Sat Jun 21 20:35:36 2014 -0700
1.3 @@ -1,10 +1,13 @@
1.4 package org.libsdl.app;
1.5
1.6 +import java.io.IOException;
1.7 +import java.io.InputStream;
1.8 import java.util.ArrayList;
1.9 import java.util.Arrays;
1.10 import java.util.Collections;
1.11 import java.util.Comparator;
1.12 import java.util.List;
1.13 +import java.lang.reflect.Method;
1.14
1.15 import android.app.*;
1.16 import android.content.*;
1.17 @@ -20,7 +23,6 @@
1.18 import android.media.*;
1.19 import android.hardware.*;
1.20
1.21 -
1.22 /**
1.23 SDL Activity
1.24 */
1.25 @@ -296,6 +298,7 @@
1.26 int is_accelerometer, int nbuttons,
1.27 int naxes, int nhats, int nballs);
1.28 public static native int nativeRemoveJoystick(int device_id);
1.29 + public static native String nativeGetHint(String name);
1.30
1.31 /**
1.32 * This method is called by SDL using JNI.
1.33 @@ -531,7 +534,52 @@
1.34 mJoystickHandler.pollInputDevices();
1.35 }
1.36 }
1.37 -
1.38 +
1.39 + // APK extension files support
1.40 +
1.41 + /** com.android.vending.expansion.zipfile.ZipResourceFile object or null. */
1.42 + private Object expansionFile;
1.43 +
1.44 + /** com.android.vending.expansion.zipfile.ZipResourceFile's getInputStream() or null. */
1.45 + private Method expansionFileMethod;
1.46 +
1.47 + public InputStream openAPKExtensionInputStream(String fileName) throws IOException {
1.48 + // Get a ZipResourceFile representing a merger of both the main and patch files
1.49 + if (expansionFile == null) {
1.50 + Integer mainVersion = Integer.parseInt(nativeGetHint("SDL_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION"));
1.51 + Integer patchVersion = Integer.parseInt(nativeGetHint("SDL_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION"));
1.52 +
1.53 + try {
1.54 + // To avoid direct dependency on Google APK extension library that is
1.55 + // not a part of Android SDK we access it using reflection
1.56 + expansionFile = Class.forName("com.android.vending.expansion.zipfile.APKExpansionSupport")
1.57 + .getMethod("getAPKExpansionZipFile", Context.class, int.class, int.class)
1.58 + .invoke(null, this, mainVersion, patchVersion);
1.59 +
1.60 + expansionFileMethod = expansionFile.getClass()
1.61 + .getMethod("getInputStream", String.class);
1.62 + } catch (Exception ex) {
1.63 + ex.printStackTrace();
1.64 + expansionFile = null;
1.65 + expansionFileMethod = null;
1.66 + }
1.67 + }
1.68 +
1.69 + // Get an input stream for a known file inside the expansion file ZIPs
1.70 + InputStream fileStream;
1.71 + try {
1.72 + fileStream = (InputStream)expansionFileMethod.invoke(expansionFile, fileName);
1.73 + } catch (Exception ex) {
1.74 + ex.printStackTrace();
1.75 + fileStream = null;
1.76 + }
1.77 +
1.78 + if (fileStream == null) {
1.79 + throw new IOException();
1.80 + }
1.81 +
1.82 + return fileStream;
1.83 + }
1.84 }
1.85
1.86 /**
2.1 --- a/include/SDL_hints.h Sat Jun 21 17:31:36 2014 -0700
2.2 +++ b/include/SDL_hints.h Sat Jun 21 20:35:36 2014 -0700
2.3 @@ -457,6 +457,16 @@
2.4 */
2.5 #define SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES "SDL_VIDEO_MAC_FULLSCREEN_SPACES"
2.6
2.7 +/**
2.8 + * \brief Android APK expansion main file version. Should be a string number like "1", "2" etc.
2.9 + */
2.10 +#define SDL_HINT_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION "SDL_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION"
2.11 +
2.12 +/**
2.13 + * \brief Android APK expansion patch file version. Should be a string number like "1", "2" etc.
2.14 + */
2.15 +#define SDL_HINT_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION "SDL_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION"
2.16 +
2.17
2.18 /**
2.19 * \brief An enumeration of hint priorities
3.1 --- a/src/core/android/SDL_android.c Sat Jun 21 17:31:36 2014 -0700
3.2 +++ b/src/core/android/SDL_android.c Sat Jun 21 20:35:36 2014 -0700
3.3 @@ -385,7 +385,15 @@
3.4 (*env)->ReleaseStringUTFChars(env, text, utftext);
3.5 }
3.6
3.7 +jstring Java_org_libsdl_app_SDLActivity_nativeGetHint(JNIEnv* env, jclass cls, jstring name) {
3.8 + const char *utfname = (*env)->GetStringUTFChars(env, name, NULL);
3.9 + const char *hint = SDL_GetHint(utfname);
3.10
3.11 + jstring result = (*env)->NewStringUTF(env, hint);
3.12 + (*env)->ReleaseStringUTFChars(env, name, utfname);
3.13 +
3.14 + return result;
3.15 +}
3.16
3.17 /*******************************************************************************
3.18 Functions called by SDL into Java
3.19 @@ -758,7 +766,14 @@
3.20 "open", "(Ljava/lang/String;I)Ljava/io/InputStream;");
3.21 inputStream = (*mEnv)->CallObjectMethod(mEnv, assetManager, mid, fileNameJString, 1 /* ACCESS_RANDOM */);
3.22 if (Android_JNI_ExceptionOccurred(false)) {
3.23 - goto failure;
3.24 + // Try fallback to APK Extension files
3.25 + mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, context),
3.26 + "openAPKExtensionInputStream", "(Ljava/lang/String;)Ljava/io/InputStream;");
3.27 + inputStream = (*mEnv)->CallObjectMethod(mEnv, context, mid, fileNameJString);
3.28 +
3.29 + if (Android_JNI_ExceptionOccurred(false)) {
3.30 + goto failure;
3.31 + }
3.32 }
3.33
3.34 ctx->hidden.androidio.inputStreamRef = (*mEnv)->NewGlobalRef(mEnv, inputStream);