Commit 758156a765dd8dd3ab482bd7b89b049da38053f1

Sam Lantinga 2017-11-04T09:37:29

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.

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 c5520f8..be8aecc 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 04a5f24..28f9a19 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;
-    }
-
-    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 (!mActivityClass || !midGetManifestEnvironmentVariables) {
+        __android_log_print(ANDROID_LOG_WARN, "SDL", "Request to get environment variables before JNI is ready");
+        return;
     }
 
-    if (SDL_AndroidEnvMem) {
-        SDL_free(SDL_AndroidEnvMem);
-        SDL_AndroidEnvMem = NULL;
+    if (!bHasEnvironmentVariables) {
+        JNIEnv *env = Android_JNI_GetEnv();
+        (*env)->CallStaticVoidMethod(env, mActivityClass, midGetManifestEnvironmentVariables);
     }
-
-    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 06d40e2..4e7acbe 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 f24e4c0..ddb2e1e 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(__ANDROID__)
+#if defined(HAVE_GETENV)
 char *
 SDL_getenv(const char *name)
 {
-    /* Input validation */
-    if (!name || SDL_strlen(name)==0) {
-        return NULL;
-    }
+#if defined(__ANDROID__)
+    /* 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;
     }