Commit 8fd0c22adc13ac85b27e89981e81870d88bfa62b

Sam Lantinga 2017-10-24T00:17:07

Added the ability to set SDL hints from AndroidManifest.xml (thanks Rachel!) This is especially useful for things like the accelerometer hint which could be needed before application main().

diff --git a/android-project/app/src/main/AndroidManifest.xml b/android-project/app/src/main/AndroidManifest.xml
index ca5cdf3..0116491 100644
--- a/android-project/app/src/main/AndroidManifest.xml
+++ b/android-project/app/src/main/AndroidManifest.xml
@@ -8,6 +8,10 @@
     android:versionName="1.0"
     android:installLocation="auto">
 
+    <!-- Example of setting SDL hints from AndroidManifest.xml:
+    <meta-data android:value="0" android:name="SDL_ENV.SDL_ACCELEROMETER_AS_JOYSTICK"/>
+     -->
+     
     <!-- Android 4.0.1 -->
     <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="16" />
 
diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
index 7807fc7..5d2ef4a 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
@@ -24,6 +24,8 @@ import android.graphics.*;
 import android.graphics.drawable.Drawable;
 import android.hardware.*;
 import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ApplicationInfo;
 
 /**
     SDL Activity
@@ -613,6 +615,29 @@ public class SDLActivity extends Activity {
         return SDL.getContext();
     }
 
+    /**
+     * This method is called by SDL using JNI.
+     */
+    public static String getManifestEnvironmentVariable(String variableName) {
+        try {
+            ApplicationInfo applicationInfo = getContext().getPackageManager().getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA);
+            if (applicationInfo.metaData == null) {
+                return null;
+            }
+
+            String key = "SDL_ENV." + variableName;
+            if (!applicationInfo.metaData.containsKey(key)) {
+                return null;
+            }
+
+            return applicationInfo.metaData.get(key).toString();
+        }
+        catch (PackageManager.NameNotFoundException e)
+        {
+            return null;
+        }
+    }
+
     static class ShowTextInputTask implements Runnable {
         /*
          * This is used to regulate the pan&scan method to have some offset from
diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c
index 48cf7b7..c3a9ba5 100644
--- a/src/core/android/SDL_android.c
+++ b/src/core/android/SDL_android.c
@@ -211,6 +211,7 @@ static jmethodID midClipboardSetText;
 static jmethodID midClipboardGetText;
 static jmethodID midClipboardHasText;
 static jmethodID midOpenAPKExpansionInputStream;
+static jmethodID midGetManifestEnvironmentVariable;
 
 /* audio manager */
 static jclass mAudioManagerClass;
@@ -310,11 +311,14 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv* mEnv, jclass c
     midOpenAPKExpansionInputStream = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
                                 "openAPKExpansionInputStream", "(Ljava/lang/String;)Ljava/io/InputStream;");
 
+    midGetManifestEnvironmentVariable = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
+                                "getManifestEnvironmentVariable", "(Ljava/lang/String;)Ljava/lang/String;");
+
     if (!midGetNativeSurface ||
        !midSetActivityTitle || !midSetOrientation || !midGetContext || !midInputGetInputDeviceIds ||
        !midSendMessage || !midShowTextInput || !midIsScreenKeyboardShown || 
        !midClipboardSetText || !midClipboardGetText || !midClipboardHasText ||
-       !midOpenAPKExpansionInputStream) {
+       !midOpenAPKExpansionInputStream || !midGetManifestEnvironmentVariable) {
         __android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLActivity.java?");
     }
 
@@ -2034,6 +2038,41 @@ const char * SDL_AndroidGetExternalStoragePath(void)
     return s_AndroidExternalFilesPath;
 }
 
+// Ugh, but we have to SDL_strdup() our result to pass it safely back
+// out into normal SDL_getenv flow.  So we'll just do the same sort
+// of trick as on Win32 over in SDL_getenv.c.
+char *SDL_AndroidEnvMem;
+
+char *SDL_AndroidGetManifestEnvironmentVariable(const char *variableName)
+{
+    if ((mActivityClass == NULL) || (midGetManifestEnvironmentVariable == 0)) {
+        __android_log_print(ANDROID_LOG_WARN, "SDL", "request to get environment variable before JNI is ready: %s", variableName);
+        return NULL;
+    }
+
+    JNIEnv *env = Android_JNI_GetEnv();
+
+    jstring jVariableName = (*env)->NewStringUTF(env, variableName);
+    jstring jResult = (jstring)((*env)->CallStaticObjectMethod(env, mActivityClass, midGetManifestEnvironmentVariable, jVariableName));
+
+    if (jResult == NULL) {
+        return NULL;        
+    }
+
+    if (SDL_AndroidEnvMem) {
+        SDL_free(SDL_AndroidEnvMem);
+        SDL_AndroidEnvMem = NULL;
+    }
+
+    const char *result = (*env)->GetStringUTFChars(env, jResult, NULL);
+    SDL_AndroidEnvMem = SDL_strdup(result);
+    (*env)->ReleaseStringUTFChars(env, jResult, result);
+    (*env)->DeleteLocalRef(env, jResult);
+
+    __android_log_print(ANDROID_LOG_INFO, "SDL", "environment variable in metadata: %s = %s", variableName, SDL_AndroidEnvMem);
+    return SDL_AndroidEnvMem;
+}
+
 #endif /* __ANDROID__ */
 
 /* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/core/android/SDL_android.h b/src/core/android/SDL_android.h
index e0ae7b5..1d7e81a 100644
--- a/src/core/android/SDL_android.h
+++ b/src/core/android/SDL_android.h
@@ -59,6 +59,9 @@ size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer, size_t size, size_t ma
 size_t Android_JNI_FileWrite(SDL_RWops* ctx, const void* buffer, size_t size, size_t num);
 int Android_JNI_FileClose(SDL_RWops* ctx);
 
+/* Environment support */
+char *SDL_AndroidGetManifestEnvironmentVariable(const char *variableName);
+
 /* Clipboard support */
 int Android_JNI_SetClipboardText(const char* text);
 char* Android_JNI_GetClipboardText(void);
diff --git a/src/stdlib/SDL_getenv.c b/src/stdlib/SDL_getenv.c
index 305307f..f24e4c0 100644
--- a/src/stdlib/SDL_getenv.c
+++ b/src/stdlib/SDL_getenv.c
@@ -29,6 +29,10 @@
 #include "../core/windows/SDL_windows.h"
 #endif
 
+#if defined(__ANDROID__)
+#include "../core/android/SDL_android.h"
+#endif
+
 #include "SDL_stdinc.h"
 
 #if defined(__WIN32__) && (!defined(HAVE_SETENV) || !defined(HAVE_GETENV))
@@ -167,7 +171,18 @@ SDL_setenv(const char *name, const char *value, int overwrite)
 #endif
 
 /* Retrieve a variable named "name" from the environment */
-#if defined(HAVE_GETENV)
+#if defined(__ANDROID__)
+char *
+SDL_getenv(const char *name)
+{
+    /* Input validation */
+    if (!name || SDL_strlen(name)==0) {
+        return NULL;
+    }
+
+    return SDL_AndroidGetManifestEnvironmentVariable(name);    
+}
+#elif defined(HAVE_GETENV)
 char *
 SDL_getenv(const char *name)
 {