diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index ed26730a3..9c5bf3d96 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -401,6 +401,16 @@ limitations under the License. android:name=".services.TrackDeleteService" android:exported="false" android:permission="android.permission.BIND_JOB_SERVICE"/> + + + + + diff --git a/src/main/java/de/dennisguse/opentracks/settings/LocalePreference.java b/src/main/java/de/dennisguse/opentracks/settings/LocalePreference.java index 56742ffeb..95687143c 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/LocalePreference.java +++ b/src/main/java/de/dennisguse/opentracks/settings/LocalePreference.java @@ -1,25 +1,36 @@ package de.dennisguse.opentracks.settings; +import android.annotation.SuppressLint; import android.app.LocaleConfig; import android.content.Context; import android.os.Build; import android.os.LocaleList; import android.util.AttributeSet; +import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatDelegate; +import androidx.core.app.LocaleManagerCompat; import androidx.core.os.LocaleListCompat; import androidx.preference.ListPreference; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; import java.util.ArrayList; import java.util.Comparator; +import java.util.List; import java.util.Locale; +import java.util.Optional; import de.dennisguse.opentracks.R; public class LocalePreference extends ListPreference { + private String TAG = LocalePreference.class.getSimpleName(); + public LocalePreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(context); @@ -40,18 +51,17 @@ public LocalePreference(@NonNull Context context) { init(context); } + // /data/user/0/de.dennisguse.opentracks.debug/files/androidx.appcompat.app.AppCompatDelegate.application_locales_record_file: open failed: ENOENT (No such file or directory) private void init(Context context) { setPersistent(false); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { - setEnabled(false); - return; - } + LocaleItem systemDefaultLocale = new LocaleItem("", context.getString(R.string.settings_locale_system_default)); LocaleItem currentLocale = new LocaleItem(Locale.getDefault().toLanguageTag(), Locale.getDefault().getDisplayName()); // All available options - LocaleList supportedLocales = LocaleConfig.fromContextIgnoringOverride(context).getSupportedLocales(); + LocaleList supportedLocales = getLocaleListCompat(); + ArrayList localeItemsSorting = new ArrayList<>(); for (int i = 0; i < supportedLocales.size(); i++) { Locale current = supportedLocales.get(i); @@ -104,4 +114,36 @@ record LocaleItem( String displayName ) { } + + // TODO Get this functionality from any Androidx compat library: should be in LocaleListCompat or LocaleManagerCompat + // 2024-12-12: on Android 14-: LocaleManagerCompat.getApplicationLocales(getContext()) returned "[]" + // See: https://stackoverflow.com/questions/78116375/per-app-language-preferences-get-list-of-apps-available-language-programmatic + @Deprecated + private LocaleList getLocaleListCompat() { + var a = LocaleManagerCompat.getApplicationLocales(getContext()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + return LocaleConfig.fromContextIgnoringOverride(getContext()).getSupportedLocales(); + } + + @SuppressLint("DiscouragedApi") int localesConfigId = getContext().getResources().getIdentifier("_generated_res_locale_config", "xml", getContext().getPackageName()); + + List localeList = new ArrayList<>(); + XmlPullParser xpp = getContext().getResources().getXml(localesConfigId); + try { + while (xpp.getEventType() != XmlPullParser.END_DOCUMENT) { + if (xpp.getEventType() == XmlPullParser.START_TAG) { + if ("locale".equals(xpp.getName()) && xpp.getAttributeCount() > 0 && xpp.getAttributeName(0).equals("name")) { + localeList.add(xpp.getAttributeValue(0)); + } + } + xpp.next(); + } + } catch (IOException | XmlPullParserException e) { + Log.e(TAG, "Could not load locales: " + e.getMessage()); + } + Optional locales = localeList.stream().reduce((s1, s2) -> s1 + "," + s2); + return locales + .map(LocaleList::forLanguageTags) + .orElseGet(LocaleList::getEmptyLocaleList); + } }