Skip to content

Commit

Permalink
Settings: add custom language/locale chooser (SDK33+).
Browse files Browse the repository at this point in the history
Corsican was not available using Android's per-app-language-chooser.

Fixes #1974.
  • Loading branch information
dennisguse committed Nov 30, 2024
1 parent 2cc4218 commit 03d97e5
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import android.app.LocaleConfig;
import android.content.Context;
import android.os.LocaleList;

import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.os.LocaleListCompat;
import androidx.test.core.app.ApplicationProvider;

import org.junit.Test;
Expand All @@ -13,7 +17,9 @@

import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.data.models.ActivityType;
Expand Down Expand Up @@ -46,6 +52,23 @@ private static Track createTrack(Context context, Distance totalDistance, Durati
return track;
}

@Test
public void play() {
LocaleConfig a = LocaleConfig.fromContextIgnoringOverride(context);
LocaleListCompat.forLanguageTags("co");
LocaleList supportedLocales = a.getSupportedLocales();
ArrayList<Locale> sortedLocales = new ArrayList<>(supportedLocales.size());
for (int i = 0; i < supportedLocales.size(); i++) {
sortedLocales.set(i, supportedLocales.get(i));
}


LocaleListCompat.forLanguageTags("co");
var d = AppCompatDelegate.getApplicationLocales();
var e = Locale.getDefault();
a.getStatus();
}

@Test
public void testAggregate() {
// given
Expand Down
107 changes: 107 additions & 0 deletions src/main/java/de/dennisguse/opentracks/settings/LocalePreference.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package de.dennisguse.opentracks.settings;

import android.app.LocaleConfig;
import android.content.Context;
import android.os.Build;
import android.os.LocaleList;
import android.util.AttributeSet;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.os.LocaleListCompat;
import androidx.preference.ListPreference;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Locale;

import de.dennisguse.opentracks.R;

public class LocalePreference extends ListPreference {

public LocalePreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}

public LocalePreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}

public LocalePreference(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}

public LocalePreference(@NonNull Context context) {
super(context);
init(context);
}

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();
ArrayList<LocaleItem> localeItemsSorting = new ArrayList<>();
for (int i = 0; i < supportedLocales.size(); i++) {
Locale current = supportedLocales.get(i);
localeItemsSorting.add(new LocaleItem(current.toLanguageTag(), current.getDisplayName()));
}

localeItemsSorting.removeIf(current -> current.languageTag.equals(currentLocale.languageTag));
localeItemsSorting.sort(Comparator.comparing(o -> o.displayName));

ArrayList<LocaleItem> localeItemList = new ArrayList<>();
localeItemList.add(systemDefaultLocale);
localeItemList.add(currentLocale);
localeItemList.addAll(localeItemsSorting);

ArrayList<String> entries = new ArrayList<>();
ArrayList<String> entryValues = new ArrayList<>();

for (LocaleItem current : localeItemList) {
entries.add(current.displayName);
entryValues.add(current.languageTag);
}

setEntries(entries.toArray(new String[]{}));
setEntryValues(entryValues.toArray(new String[]{}));

if (AppCompatDelegate.getApplicationLocales().equals(LocaleListCompat.getEmptyLocaleList())) {
setValue(systemDefaultLocale.languageTag);
} else {
setValue(currentLocale.languageTag);
}
}

@Override
public void setOnPreferenceChangeListener(@Nullable OnPreferenceChangeListener onPreferenceChangeListener) {
super.setOnPreferenceChangeListener(onPreferenceChangeListener);
}

@Override
public boolean callChangeListener(Object newValue) {
LocaleListCompat newLocale = LocaleListCompat.getEmptyLocaleList();
if (!newValue.equals("")) {
newLocale = LocaleListCompat.forLanguageTags((String) newValue);
}
AppCompatDelegate.setApplicationLocales(newLocale);
return super.callChangeListener(newValue);
}

record LocaleItem(
String languageTag,
String displayName
) {
}
}
3 changes: 3 additions & 0 deletions src/main/res/values/settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,9 @@
<string name="settings_ui_dynamic_colors_key" translatable="false">uiDynamicColors</string>
<bool name="settings_ui_dynamic_colors_default" translatable="false">false</bool>

<!-- androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode() -->
<string name="locale_key" translatable="false">localeKey</string>

<!-- androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode() -->
<string name="night_mode_key" translatable="false">nightMode</string>
<string name="night_mode_default" translatable="false">@string/night_mode_system_value</string>
Expand Down
3 changes: 3 additions & 0 deletions src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,9 @@ limitations under the License.
<string name="settings_recording_track_name_number_option">Number</string>
<string name="settings_recording_track_name_title">Default track name</string>
<string name="settings_recording_idle_timeout_title">Idle threshold</string>
<string name="settings_locale_title">Language</string>
<string name="settings_locale_system_default">System default</string>

<string name="settings_night_mode_title">UI Theme</string>
<string name="settings_night_mode_option_system">System</string>
<string name="settings_night_mode_option_day">Day</string>
Expand Down
6 changes: 6 additions & 0 deletions src/main/res/xml/settings_user_interface.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:title="@string/settings_ui_title">

<de.dennisguse.opentracks.settings.LocalePreference
android:key="@string/locale_key"
android:persistent="false"
android:title="@string/settings_locale_title"
app:useSimpleSummaryProvider="true" />

<ListPreference
android:defaultValue="@string/night_mode_default"
android:entries="@array/night_mode_options"
Expand Down

0 comments on commit 03d97e5

Please sign in to comment.