From 758156a765dd8dd3ab482bd7b89b049da38053f1 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sat, 4 Nov 2017 09:37:29 -0700 Subject: [PATCH] Fixed bug 3917 - Android, issues with getManifestEnvironmentVariable We're going to push the manifest environment variables from the Java side instead of continually querying for them from the native side. --- .../main/java/org/libsdl/app/SDLActivity.java | 30 ++++---- src/core/android/SDL_android.c | 76 ++++++++++--------- src/core/android/SDL_android.h | 2 +- src/stdlib/SDL_getenv.c | 22 ++---- 4 files changed, 67 insertions(+), 63 deletions(-) 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 c5520f81b..be8aeccad 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 @@ -512,6 +512,8 @@ public class SDLActivity extends Activity { public static native void onNativeSurfaceChanged(); public static native void onNativeSurfaceDestroyed(); public static native String nativeGetHint(String name); + public static native void nativeSetenv(String name, String value); + public static native void nativeEnvironmentVariablesSet(); /** * This method is called by SDL using JNI. @@ -616,23 +618,25 @@ public class SDLActivity extends Activity { /** * This method is called by SDL using JNI. */ - public static String getManifestEnvironmentVariable(String variableName) { + public static void getManifestEnvironmentVariables() { try { ApplicationInfo applicationInfo = getContext().getPackageManager().getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA); - if (applicationInfo.metaData == null) { - return null; + Bundle bundle = applicationInfo.metaData; + if (bundle == null) { + return; } - - String key = "SDL_ENV." + variableName; - if (!applicationInfo.metaData.containsKey(key)) { - return null; + String prefix = "SDL_ENV."; + final int trimLength = prefix.length(); + for (String key : bundle.keySet()) { + if (key.startsWith(prefix)) { + String name = key.substring(trimLength); + String value = bundle.get(key).toString(); + nativeSetenv(name, value); + } } - - return applicationInfo.metaData.get(key).toString(); - } - catch (PackageManager.NameNotFoundException e) - { - return null; + nativeEnvironmentVariablesSet(); + } catch (Exception e) { + Log.v("SDL", "exception " + e.toString()); } } diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 04a5f245e..28f9a19d8 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -128,6 +128,13 @@ JNIEXPORT jstring JNICALL SDL_JAVA_INTERFACE(nativeGetHint)( JNIEnv* env, jclass cls, jstring name); +JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetenv)( + JNIEnv* env, jclass cls, + jstring name, jstring value); + +JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeEnvironmentVariablesSet)( + JNIEnv* env, jclass cls); + /* Java class SDLInputConnection */ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeCommitText)( JNIEnv* env, jclass cls, @@ -213,7 +220,7 @@ static jmethodID midClipboardSetText; static jmethodID midClipboardGetText; static jmethodID midClipboardHasText; static jmethodID midOpenAPKExpansionInputStream; -static jmethodID midGetManifestEnvironmentVariable; +static jmethodID midGetManifestEnvironmentVariables; static jmethodID midGetDisplayDPI; /* audio manager */ @@ -244,6 +251,8 @@ static jfieldID fidSeparateMouseAndTouch; static float fLastAccelerometer[3]; static SDL_bool bHasNewData; +static SDL_bool bHasEnvironmentVariables; + /******************************************************************************* Functions called by JNI *******************************************************************************/ @@ -314,16 +323,16 @@ 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;"); + midGetManifestEnvironmentVariables = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, + "getManifestEnvironmentVariables", "()V"); midGetDisplayDPI = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "getDisplayDPI", "()Landroid/util/DisplayMetrics;"); if (!midGetNativeSurface || !midSetActivityTitle || !midSetOrientation || !midGetContext || !midInputGetInputDeviceIds || - !midSendMessage || !midShowTextInput || !midIsScreenKeyboardShown || + !midSendMessage || !midShowTextInput || !midIsScreenKeyboardShown || !midClipboardSetText || !midClipboardGetText || !midClipboardHasText || - !midOpenAPKExpansionInputStream || !midGetManifestEnvironmentVariable || !midGetDisplayDPI) { + !midOpenAPKExpansionInputStream || !midGetManifestEnvironmentVariables|| !midGetDisplayDPI) { __android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLActivity.java?"); } @@ -808,6 +817,26 @@ JNIEXPORT jstring JNICALL SDL_JAVA_INTERFACE(nativeGetHint)( return result; } +JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetenv)( + JNIEnv* env, jclass cls, + jstring name, jstring value) +{ + const char *utfname = (*env)->GetStringUTFChars(env, name, NULL); + const char *utfvalue = (*env)->GetStringUTFChars(env, value, NULL); + + SDL_setenv(utfname, utfvalue, 1); + + (*env)->ReleaseStringUTFChars(env, name, utfname); + (*env)->ReleaseStringUTFChars(env, value, utfvalue); + +} + +JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeEnvironmentVariablesSet)( + JNIEnv* env, jclass cls) +{ + bHasEnvironmentVariables = SDL_TRUE; +} + /******************************************************************************* Functions called by SDL into Java *******************************************************************************/ @@ -2105,40 +2134,17 @@ 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) +void Android_JNI_GetManifestEnvironmentVariables(void) { - 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; + if (!mActivityClass || !midGetManifestEnvironmentVariables) { + __android_log_print(ANDROID_LOG_WARN, "SDL", "Request to get environment variables before JNI is ready"); + return; } - JNIEnv *env = Android_JNI_GetEnv(); - - jstring jVariableName = (*env)->NewStringUTF(env, variableName); - jstring jResult = (jstring)((*env)->CallStaticObjectMethod(env, mActivityClass, midGetManifestEnvironmentVariable, jVariableName)); - (*env)->DeleteLocalRef(env, jVariableName); - - if (jResult == NULL) { - return NULL; + if (!bHasEnvironmentVariables) { + JNIEnv *env = Android_JNI_GetEnv(); + (*env)->CallStaticVoidMethod(env, mActivityClass, midGetManifestEnvironmentVariables); } - - 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__ */ diff --git a/src/core/android/SDL_android.h b/src/core/android/SDL_android.h index 06d40e23a..4e7acbe40 100644 --- a/src/core/android/SDL_android.h +++ b/src/core/android/SDL_android.h @@ -62,7 +62,7 @@ size_t Android_JNI_FileWrite(SDL_RWops* ctx, const void* buffer, size_t size, si int Android_JNI_FileClose(SDL_RWops* ctx); /* Environment support */ -char *SDL_AndroidGetManifestEnvironmentVariable(const char *variableName); +void Android_JNI_GetManifestEnvironmentVariables(void); /* Clipboard support */ int Android_JNI_SetClipboardText(const char* text); diff --git a/src/stdlib/SDL_getenv.c b/src/stdlib/SDL_getenv.c index f24e4c024..ddb2e1e3a 100644 --- a/src/stdlib/SDL_getenv.c +++ b/src/stdlib/SDL_getenv.c @@ -171,23 +171,17 @@ SDL_setenv(const char *name, const char *value, int overwrite) #endif /* Retrieve a variable named "name" from the environment */ +#if defined(HAVE_GETENV) +char * +SDL_getenv(const char *name) +{ #if defined(__ANDROID__) -char * -SDL_getenv(const char *name) -{ - /* Input validation */ - if (!name || SDL_strlen(name)==0) { - return NULL; - } + /* Make sure variables from the application manifest are available */ + Android_JNI_GetManifestEnvironmentVariables(); +#endif - return SDL_AndroidGetManifestEnvironmentVariable(name); -} -#elif defined(HAVE_GETENV) -char * -SDL_getenv(const char *name) -{ /* Input validation */ - if (!name || SDL_strlen(name)==0) { + if (!name || !*name) { return NULL; }