From 8fd0c22adc13ac85b27e89981e81870d88bfa62b Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 24 Oct 2017 00:17:07 -0700 Subject: [PATCH] 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(). --- .../app/src/main/AndroidManifest.xml | 4 ++ .../main/java/org/libsdl/app/SDLActivity.java | 25 +++++++++++ src/core/android/SDL_android.c | 41 ++++++++++++++++++- src/core/android/SDL_android.h | 3 ++ src/stdlib/SDL_getenv.c | 17 +++++++- 5 files changed, 88 insertions(+), 2 deletions(-) diff --git a/android-project/app/src/main/AndroidManifest.xml b/android-project/app/src/main/AndroidManifest.xml index ca5cdf394..011649151 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"> + + 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 7807fc7b2..5d2ef4adc 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 48cf7b796..c3a9ba5f3 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 e0ae7b5b3..1d7e81aa7 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 305307feb..f24e4c024 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) {