Skip to content

Commit

Permalink
Fix #13130: Android respects device locale (#19419)
Browse files Browse the repository at this point in the history
Co-authored-by: Tulio Leao <tupaschoal@gmail.com>
  • Loading branch information
undermark5 and tupaschoal committed Apr 13, 2023
1 parent 0a28f6b commit 78aa02f
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 3 deletions.
1 change: 1 addition & 0 deletions distribution/changelog.txt
Expand Up @@ -9,6 +9,7 @@
- Improved: [#19764] Miscellaneous scenery tab now grouped next to the all-scenery tab.
- Improved: [#19830] “Highlight path issues” will now hide wall elements.
- Fix: [#12598] Number of holes is not set correctly when saving track designs.
- Fix: [#13130] Android always defaulting to UK locale for language, currency and temperature.
- Fix: [#18895] Responding mechanic blocked at level crossing.
- Fix: [#19231] Crash due to null pointer to previously deleted banner in tile copy/paste functionality
- Fix: [#19296] Crash due to a race condition for parallel object loading.
Expand Down
@@ -1,15 +1,80 @@
package io.openrct2;

import android.icu.util.Currency;
import android.icu.util.LocaleData;
import android.icu.util.ULocale;
import android.os.Build;
import android.view.View;

import org.libsdl.app.SDLActivity;

import java.util.Locale;

public class GameActivity extends SDLActivity {

public float getDefaultScale() {
return getResources().getDisplayMetrics().density;
}

public String getDefaultLocale(String[] supportedTags) {
Locale deviceLocale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
deviceLocale = getResources().getConfiguration().getLocales().get(0);
} else {
deviceLocale = getResources().getConfiguration().locale;
}

for (String supportedTag : supportedTags) {
if (supportedTag.isEmpty()) continue;
String[] splits = supportedTag.split("-");
String language = splits[0];
String country = splits[1];
if (deviceLocale.getLanguage().equals(language) && deviceLocale.getCountry().equals(country)) {
return supportedTag;
}
}

Locale canadaEn = Locale.CANADA;
if (canadaEn.getLanguage().equals(deviceLocale.getLanguage()) && canadaEn.getCountry().equals(deviceLocale.getCountry())) {
return "en-US";
}

for (String supportedTag : supportedTags) {
if (supportedTag.isEmpty()) continue;
String[] splits = supportedTag.split("-");
String language = splits[0];
if (deviceLocale.getLanguage().equals(language)) {
return supportedTag;
}
}
return "en-UK";
}

public String getLocaleCurrency() {
Locale deviceLocale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
deviceLocale = getResources().getConfiguration().getLocales().get(0);
return Currency.getInstance(deviceLocale).getCurrencyCode();
} else {
deviceLocale = getResources().getConfiguration().locale;
return java.util.Currency.getInstance(deviceLocale).getCurrencyCode();
}
}

public boolean isImperialLocaleMeasurementFormat() {
Locale deviceLocale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
return LocaleData.getMeasurementSystem(ULocale.forLocale(getResources().getConfiguration().getLocales().get(0))) == LocaleData.MeasurementSystem.US;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
deviceLocale = getResources().getConfiguration().getLocales().get(0);
} else {
deviceLocale = getResources().getConfiguration().locale;
}
String localeCountry = deviceLocale.getCountry();
return localeCountry.equals(Locale.US.getCountry()) || localeCountry.equals(new Locale("xx", "LR").getCountry()) || localeCountry.equals(new Locale("xx", "MM").getCountry());
}

@Override
protected String[] getLibraries() {
return new String[]{
Expand Down
63 changes: 60 additions & 3 deletions src/openrct2/platform/Platform.Android.cpp
Expand Up @@ -74,17 +74,74 @@ namespace Platform

uint16_t GetLocaleLanguage()
{
return LANGUAGE_ENGLISH_UK;
JNIEnv* env = static_cast<JNIEnv*>(SDL_AndroidGetJNIEnv());

jobject activity = static_cast<jobject>(SDL_AndroidGetActivity());
jclass activityClass = env->GetObjectClass(activity);
jmethodID getDefaultLocale = env->GetMethodID(
activityClass, "getDefaultLocale", "([Ljava/lang/String;)Ljava/lang/String;");

jobjectArray jLanguageTags = env->NewObjectArray(
LANGUAGE_COUNT, env->FindClass("java/lang/String"), env->NewStringUTF(""));

for (int32_t i = 1; i < LANGUAGE_COUNT; ++i)
{
jstring jTag = env->NewStringUTF(LanguagesDescriptors[i].locale);
env->SetObjectArrayElement(jLanguageTags, i, jTag);
}

jstring jniString = static_cast<jstring>(env->CallObjectMethod(activity, getDefaultLocale, jLanguageTags));

const char* jniChars = env->GetStringUTFChars(jniString, nullptr);
std::string defaultLocale = jniChars;

env->ReleaseStringUTFChars(jniString, jniChars);
for (int32_t i = 0; i < LANGUAGE_COUNT; ++i)
{
jobject strToFree = env->GetObjectArrayElement(jLanguageTags, i);
env->DeleteLocalRef(strToFree);
}
env->DeleteLocalRef(jLanguageTags);
env->DeleteLocalRef(activity);
env->DeleteLocalRef(activityClass);

return LanguageGetIDFromLocale(defaultLocale.c_str());
}

CurrencyType GetLocaleCurrency()
{
return Platform::GetCurrencyValue(NULL);
JNIEnv* env = static_cast<JNIEnv*>(SDL_AndroidGetJNIEnv());

jobject activity = static_cast<jobject>(SDL_AndroidGetActivity());
jclass activityClass = env->GetObjectClass(activity);
jmethodID getDefaultLocale = env->GetMethodID(activityClass, "getLocaleCurrency", "()Ljava/lang/String;");

jstring jniString = static_cast<jstring>(env->CallObjectMethod(activity, getDefaultLocale));

const char* jniChars = env->GetStringUTFChars(jniString, nullptr);
std::string localeCurrencyCode = jniChars;

env->ReleaseStringUTFChars(jniString, jniChars);
env->DeleteLocalRef(activity);
env->DeleteLocalRef(activityClass);

return Platform::GetCurrencyValue(localeCurrencyCode.c_str());
}

MeasurementFormat GetLocaleMeasurementFormat()
{
return MeasurementFormat::Metric;
JNIEnv* env = static_cast<JNIEnv*>(SDL_AndroidGetJNIEnv());

jobject activity = static_cast<jobject>(SDL_AndroidGetActivity());
jclass activityClass = env->GetObjectClass(activity);
jmethodID getIsImperialLocaleMeasurementFormat = env->GetMethodID(
activityClass, "isImperialLocaleMeasurementFormat", "()Z");

jboolean isImperial = env->CallBooleanMethod(activity, getIsImperialLocaleMeasurementFormat);

env->DeleteLocalRef(activity);
env->DeleteLocalRef(activityClass);
return isImperial == JNI_TRUE ? MeasurementFormat::Imperial : MeasurementFormat::Metric;
}

std::string GetSteamPath()
Expand Down

0 comments on commit 78aa02f

Please sign in to comment.