SDL: get preferred locales on android (4d3cd)

From 4d3cdb70b5afab53082335e8ea01eaf93b9d9f28 Mon Sep 17 00:00:00 2001
From: kyle-sylvestre <[EMAIL REDACTED]>
Date: Tue, 20 May 2025 18:09:28 -0400
Subject: [PATCH] get preferred locales on android

(cherry picked from commit 8e221942177922e6bc7614afef03f4231a5f54b0)
---
 android-project/app/proguard-rules.pro        |  2 +
 .../main/java/org/libsdl/app/SDLActivity.java | 43 +++++++++++
 src/core/android/SDL_android.c                | 74 +++++--------------
 3 files changed, 62 insertions(+), 57 deletions(-)

diff --git a/android-project/app/proguard-rules.pro b/android-project/app/proguard-rules.pro
index 1eeb90e2c322c..5f8ee6a25ec1f 100644
--- a/android-project/app/proguard-rules.pro
+++ b/android-project/app/proguard-rules.pro
@@ -51,6 +51,8 @@
     boolean supportsRelativeMouse();
     int openFileDescriptor(java.lang.String, java.lang.String);
     boolean showFileDialog(java.lang.String[], boolean, boolean, int);
+    java.lang.String getPreferredLocales();
+    java.lang.String formatLocale(java.util.Locale);
 }
 
 -keep,includedescriptorclasses,allowoptimization class org.libsdl.app.HIDDeviceManager {
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 073351c7561f6..1dbf6591a0f94 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
@@ -23,6 +23,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.LocaleList;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.util.DisplayMetrics;
@@ -2116,6 +2117,48 @@ static class SDLFileDialogState {
         int requestCode;
         boolean multipleChoice;
     }
+    
+    /**
+     * This method is called by SDL using JNI.
+     */
+    public static String getPreferredLocales() {
+        String result = "";
+        if (Build.VERSION.SDK_INT >= 24 /* Android 7 (N) */) {
+            LocaleList locales = LocaleList.getAdjustedDefault();
+            for (int i = 0; i < locales.size(); i++) {
+                if (i != 0) result += ",";
+                result += formatLocale(locales.get(i));
+            }
+        }
+        else if (mCurrentLocale != null) {
+            result = formatLocale(mCurrentLocale);
+        }
+        return result;
+    }
+
+    public static String formatLocale(Locale locale) {
+        String result = "";
+        String lang = "";
+        if (locale.getLanguage() == "in") {
+            // Indonesian is "id" according to ISO 639.2, but on Android is "in" because of Java backwards compatibility
+            lang = "id";
+        }
+        else if (locale.getLanguage() == "") {
+            // Make sure language is never empty
+            lang = "und";
+        }
+        else {
+            lang = locale.getLanguage();
+        }
+
+        if (locale.getCountry() == "") {
+            result = lang;
+        }
+        else {
+            result = lang + "_" + locale.getCountry();
+        }
+        return result;
+    }
 }
 
 /**
diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c
index eb450979a2311..1cc9ccdb4e4ff 100644
--- a/src/core/android/SDL_android.c
+++ b/src/core/android/SDL_android.c
@@ -371,6 +371,7 @@ static jmethodID midShowTextInput;
 static jmethodID midSupportsRelativeMouse;
 static jmethodID midOpenFileDescriptor;
 static jmethodID midShowFileDialog;
+static jmethodID midGetPreferredLocales;
 
 // audio manager
 static jclass mAudioManagerClass;
@@ -660,6 +661,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
     midSupportsRelativeMouse = (*env)->GetStaticMethodID(env, mActivityClass, "supportsRelativeMouse", "()Z");
     midOpenFileDescriptor = (*env)->GetStaticMethodID(env, mActivityClass, "openFileDescriptor", "(Ljava/lang/String;Ljava/lang/String;)I");
     midShowFileDialog = (*env)->GetStaticMethodID(env, mActivityClass, "showFileDialog", "([Ljava/lang/String;ZZI)Z");
+    midGetPreferredLocales = (*env)->GetStaticMethodID(env, mActivityClass, "getPreferredLocales", "()Ljava/lang/String;");
 
     if (!midClipboardGetText ||
         !midClipboardHasText ||
@@ -691,7 +693,8 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
         !midShowTextInput ||
         !midSupportsRelativeMouse ||
         !midOpenFileDescriptor ||
-        !midShowFileDialog) {
+        !midShowFileDialog ||
+        !midGetPreferredLocales) {
         __android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLActivity.java?");
     }
 
@@ -2585,65 +2588,22 @@ bool Android_JNI_ShowToast(const char *message, int duration, int gravity, int x
 
 bool Android_JNI_GetLocale(char *buf, size_t buflen)
 {
-    AConfiguration *cfg;
-
-    SDL_assert(buflen > 6);
-
-    // Need to re-create the asset manager if locale has changed (SDL_EVENT_LOCALE_CHANGED)
-    Internal_Android_Destroy_AssetManager();
-
-    if (!asset_manager) {
-        Internal_Android_Create_AssetManager();
-    }
-
-    if (!asset_manager) {
-        return false;
-    }
-
-    cfg = AConfiguration_new();
-    if (!cfg) {
-        return false;
-    }
-
-    {
-        char language[2] = {};
-        char country[2] = {};
-        size_t id = 0;
-
-        AConfiguration_fromAssetManager(cfg, asset_manager);
-        AConfiguration_getLanguage(cfg, language);
-        AConfiguration_getCountry(cfg, country);
-
-        // Indonesian is "id" according to ISO 639.2, but on Android is "in" because of Java backwards compatibility
-        if (language[0] == 'i' && language[1] == 'n') {
-            language[1] = 'd';
-        }
-
-        // copy language (not null terminated)
-        if (language[0]) {
-            buf[id++] = language[0];
-            if (language[1]) {
-                buf[id++] = language[1];
-            }
-        }
-
-        buf[id++] = '_';
-
-        // copy country (not null terminated)
-        if (country[0]) {
-            buf[id++] = country[0];
-            if (country[1]) {
-                buf[id++] = country[1];
+    bool result = false;
+    if (buf && buflen > 0) {
+        *buf = '\0';
+        JNIEnv *env = Android_JNI_GetEnv();
+        jstring string = (jstring)(*env)->CallStaticObjectMethod(env, mActivityClass, midGetPreferredLocales);
+        if (string) {
+            const char *utf8string = (*env)->GetStringUTFChars(env, string, NULL);
+            if (utf8string) {
+                result = true;
+                SDL_strlcpy(buf, utf8string, buflen);
+                (*env)->ReleaseStringUTFChars(env, string, utf8string);
             }
+            (*env)->DeleteLocalRef(env, string);
         }
-
-        buf[id++] = '\0';
-        SDL_assert(id <= buflen);
     }
-
-    AConfiguration_delete(cfg);
-
-    return true;
+    return result;
 }
 
 bool Android_JNI_OpenURL(const char *url)