Skip to content

Commit 6f27e27

Browse files
committed
Enable changing languages from Android Settings in Android 13 onwards
To reflect the language change, the language setting in App Manager must be set to "Auto" as it takes priority over the system language. Signed-off-by: Muntashir Al-Islam <muntashirakon@riseup.net>
1 parent 73944c6 commit 6f27e27

5 files changed

Lines changed: 77 additions & 57 deletions

File tree

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@
162162
android:icon="@mipmap/ic_launcher"
163163
android:label="@string/app_name"
164164
android:largeHeap="true"
165+
android:localeConfig="@xml/locales_config"
165166
android:networkSecurityConfig="@xml/network_security_config"
166167
android:requestLegacyExternalStorage="true"
167168
android:roundIcon="@mipmap/ic_launcher_round"

app/src/main/java/io/github/muntashirakon/AppManager/settings/MainPreferences.java

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88

99
import androidx.annotation.NonNull;
1010
import androidx.annotation.Nullable;
11-
import androidx.collection.ArrayMap;
1211
import androidx.fragment.app.FragmentActivity;
1312
import androidx.lifecycle.ViewModelProvider;
1413
import androidx.preference.Preference;
1514

1615
import java.util.Arrays;
1716
import java.util.List;
1817
import java.util.Locale;
18+
import java.util.Map;
1919

2020
import io.github.muntashirakon.AppManager.R;
2121
import io.github.muntashirakon.AppManager.misc.DeviceInfo2;
@@ -66,15 +66,17 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
6666
fundingCampaignNotice.setVisible(FundingCampaignChecker.campaignRunning());
6767
// Custom locale
6868
mCurrentLang = Prefs.Appearance.getLanguage();
69-
ArrayMap<String, Locale> locales = LangUtils.getAppLanguages(mActivity);
69+
Map<String, Locale> locales = LangUtils.getAppLanguages(mActivity);
7070
final CharSequence[] languageNames = getLanguagesL(locales);
7171
final String[] languages = new String[languageNames.length];
72-
for (int i = 0; i < locales.size(); ++i) {
73-
languages[i] = locales.keyAt(i);
74-
}
75-
int localeIndex = locales.indexOfKey(mCurrentLang);
76-
if (localeIndex < 0) {
77-
localeIndex = locales.indexOfKey(LangUtils.LANG_AUTO);
72+
int i = 0;
73+
int localeIndex = 0;
74+
for (Map.Entry<String, Locale> localeEntry : locales.entrySet()) {
75+
languages[i] = localeEntry.getKey();
76+
if (languages[i].equals(mCurrentLang)) {
77+
localeIndex = i;
78+
}
79+
++i;
7880
}
7981
Preference locale = requirePreference("custom_locale");
8082
locale.setSummary(languageNames[localeIndex]);
@@ -139,14 +141,16 @@ public int getTitle() {
139141
}
140142

141143
@NonNull
142-
private CharSequence[] getLanguagesL(@NonNull ArrayMap<String, Locale> locales) {
144+
private CharSequence[] getLanguagesL(@NonNull Map<String, Locale> locales) {
143145
CharSequence[] localesL = new CharSequence[locales.size()];
144146
Locale locale;
145-
for (int i = 0; i < locales.size(); ++i) {
146-
locale = locales.valueAt(i);
147-
if (LangUtils.LANG_AUTO.equals(locales.keyAt(i))) {
147+
int i = 0;
148+
for (Map.Entry<String, Locale> localeEntry : locales.entrySet()) {
149+
locale = localeEntry.getValue();
150+
if (LangUtils.LANG_AUTO.equals(localeEntry.getKey())) {
148151
localesL[i] = mActivity.getString(R.string.auto);
149152
} else localesL[i] = locale.getDisplayName(locale);
153+
++i;
150154
}
151155
return localesL;
152156
}

app/src/main/java/io/github/muntashirakon/AppManager/utils/LangUtils.java

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,47 +6,46 @@
66
import android.content.Context;
77
import android.content.res.Configuration;
88
import android.content.res.Resources;
9+
import android.content.res.XmlResourceParser;
910
import android.os.Build;
1011

1112
import androidx.annotation.NonNull;
12-
import androidx.collection.ArrayMap;
1313
import androidx.core.os.ConfigurationCompat;
1414

15+
import org.xmlpull.v1.XmlPullParser;
16+
import org.xmlpull.v1.XmlPullParserException;
17+
18+
import java.io.IOException;
19+
import java.util.ArrayList;
1520
import java.util.IllformedLocaleException;
21+
import java.util.LinkedHashMap;
22+
import java.util.List;
1623
import java.util.Locale;
24+
import java.util.Map;
1725

1826
import io.github.muntashirakon.AppManager.R;
1927
import io.github.muntashirakon.AppManager.settings.Prefs;
2028

2129
public final class LangUtils {
2230
public static final String LANG_AUTO = "auto";
23-
public static final String LANG_DEFAULT = "en";
2431

25-
private static ArrayMap<String, Locale> sLocaleMap;
32+
private static Map<String, Locale> sLocaleMap;
2633

2734
@SuppressLint("AppBundleLocaleChanges") // We don't use Play Store
2835
private static void loadAppLanguages(@NonNull Context context) {
29-
if (sLocaleMap == null) sLocaleMap = new ArrayMap<>();
36+
if (sLocaleMap == null) sLocaleMap = new LinkedHashMap<>();
3037
Resources res = context.getResources();
3138
Configuration conf = res.getConfiguration();
32-
String[] locales = context.getResources().getStringArray(R.array.languages_key);
33-
Locale appDefaultLocale = Locale.forLanguageTag(LANG_DEFAULT);
3439

35-
for (String locale : locales) {
40+
sLocaleMap.put(LANG_AUTO, null);
41+
for (String locale : parseLocalesConfig(context)) {
3642
conf.setLocale(Locale.forLanguageTag(locale));
37-
Context ctx = context.createConfigurationContext(conf);
38-
String langTag = ctx.getString(R.string._lang_tag);
39-
40-
if (LANG_AUTO.equals(locale)) {
41-
sLocaleMap.put(LANG_AUTO, null);
42-
} else if (LANG_DEFAULT.equals(langTag)) {
43-
sLocaleMap.put(LANG_DEFAULT, appDefaultLocale);
44-
} else sLocaleMap.put(locale, ConfigurationCompat.getLocales(conf).get(0));
43+
sLocaleMap.put(locale, ConfigurationCompat.getLocales(conf).get(0));
4544
}
4645
}
4746

4847
@NonNull
49-
public static ArrayMap<String, Locale> getAppLanguages(@NonNull Context context) {
48+
public static Map<String, Locale> getAppLanguages(@NonNull Context context) {
5049
if (sLocaleMap == null) loadAppLanguages(context);
5150
return sLocaleMap;
5251
}
@@ -84,4 +83,24 @@ public static String getSeparatorString() {
8483
}
8584
return ": ";
8685
}
86+
87+
@NonNull
88+
public static List<String> parseLocalesConfig(@NonNull Context context) {
89+
List<String> localeNames = new ArrayList<>();
90+
91+
try (XmlResourceParser parser = context.getResources().getXml(R.xml.locales_config)) {
92+
int eventType = parser.getEventType();
93+
while (eventType != XmlPullParser.END_DOCUMENT) {
94+
if (eventType == XmlPullParser.START_TAG && "locale".equals(parser.getName())) {
95+
String localeName = parser.getAttributeValue("http://schemas.android.com/apk/res/android", "name");
96+
if (localeName != null) {
97+
localeNames.add(localeName);
98+
}
99+
}
100+
eventType = parser.next();
101+
}
102+
} catch (XmlPullParserException | IOException ignore) {
103+
}
104+
return localeNames;
105+
}
87106
}

app/src/main/res/values/languages.xml

Lines changed: 0 additions & 29 deletions
This file was deleted.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
3+
<locale android:name="ar"/>
4+
<locale android:name="de"/>
5+
<locale android:name="en"/>
6+
<locale android:name="es-ES"/>
7+
<locale android:name="fa"/>
8+
<locale android:name="fr"/>
9+
<locale android:name="hi"/>
10+
<locale android:name="id"/>
11+
<locale android:name="it"/>
12+
<locale android:name="ja"/>
13+
<locale android:name="ko"/>
14+
<locale android:name="nb-NO"/>
15+
<locale android:name="pl"/>
16+
<locale android:name="pt"/>
17+
<locale android:name="pt-BR"/>
18+
<locale android:name="ro"/>
19+
<locale android:name="ru-RU"/>
20+
<locale android:name="tr-TR"/>
21+
<locale android:name="uk-UA"/>
22+
<locale android:name="vi"/>
23+
<locale android:name="zh-CN"/>
24+
<locale android:name="zh-TW"/>
25+
</locale-config>

0 commit comments

Comments
 (0)