Compare commits

...

12 Commits

Author SHA1 Message Date
akwizgran
e24728055c Update lint suppressions. 2021-02-09 11:15:01 +00:00
akwizgran
b2dc99bf26 Remove code that's only needed on API 15. 2021-02-09 11:15:01 +00:00
akwizgran
50d144c917 Avoid repeated calls to Resources.getSystem(). 2021-02-09 11:15:01 +00:00
goapunk
da7f57e0af update notifications on system language change 2021-02-09 11:15:01 +00:00
Julian Dehm
2374f8b4c9 address review 2021-02-09 11:15:01 +00:00
goapunk
5b77f28ce0 Skip setting the locale if system default is used 2021-02-09 11:15:00 +00:00
goapunk
c247e3aa4e Hardcode unsupported native language names 2021-02-09 11:15:00 +00:00
goapunk
8e0b71c76f Force locale on account deletion 2021-02-09 11:15:00 +00:00
goapunk
88f57893e8 Don't show unsupported locales in the settings 2021-02-09 11:14:58 +00:00
Julian Dehm
b111abb484 Set Locale only once 2021-02-09 11:14:16 +00:00
goapunk
4415598d3d Respect the deprecation of updateConfiguration 2021-02-09 11:14:16 +00:00
goapunk
40e14d3e94 Update the system configuration locale 2021-02-09 11:14:15 +00:00
6 changed files with 141 additions and 40 deletions

View File

@@ -25,7 +25,7 @@ class BriarAccountManager extends AndroidAccountManager {
public void deleteAccount() { public void deleteAccount() {
synchronized (stateChangeLock) { synchronized (stateChangeLock) {
super.deleteAccount(); super.deleteAccount();
Localizer.reinitialize(); Localizer.reinitialize(appContext);
UiUtils.setTheme(appContext, UiUtils.setTheme(appContext,
appContext.getString(R.string.pref_theme_light_value)); appContext.getString(R.string.pref_theme_light_value));
} }

View File

@@ -579,6 +579,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
@UiThread @UiThread
private void updateContactAddedNotification() { private void updateContactAddedNotification() {
if (contactAddedTotal == 0) return;
BriarNotificationBuilder b = BriarNotificationBuilder b =
new BriarNotificationBuilder(appContext, CONTACT_CHANNEL_ID); new BriarNotificationBuilder(appContext, CONTACT_CHANNEL_ID);
b.setSmallIcon(R.drawable.notification_contact_added); b.setSmallIcon(R.drawable.notification_contact_added);
@@ -713,4 +714,16 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
public void unblockAllBlogPostNotifications() { public void unblockAllBlogPostNotifications() {
androidExecutor.runOnUiThread((Runnable) () -> blockBlogs = false); androidExecutor.runOnUiThread((Runnable) () -> blockBlogs = false);
} }
@Override
public void restartNotifications(boolean locked, boolean mayAlertAgain) {
androidExecutor.runOnUiThread(() -> {
updateForegroundNotification(locked);
updateContactNotification(mayAlertAgain);
updateBlogPostNotification(mayAlertAgain);
updateForumPostNotification(mayAlertAgain);
updateGroupMessageNotification(mayAlertAgain);
updateContactAddedNotification();
});
}
} }

View File

@@ -81,6 +81,7 @@ public class BriarApplicationImpl extends Application
rootLogger.setLevel(IS_DEBUG_BUILD ? FINE : INFO); rootLogger.setLevel(IS_DEBUG_BUILD ? FINE : INFO);
LOG.info("Created"); LOG.info("Created");
Localizer.getInstance().setLocaleLegacy(this);
EmojiManager.install(new GoogleEmojiProvider()); EmojiManager.install(new GoogleEmojiProvider());
} }
@@ -104,7 +105,9 @@ public class BriarApplicationImpl extends Application
@Override @Override
public void onConfigurationChanged(@NonNull Configuration newConfig) { public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig); super.onConfigurationChanged(newConfig);
Localizer.getInstance().setLocale(this); Localizer.getInstance().applicationConfigurationChanged(this, newConfig,
applicationComponent.androidNotificationManager(),
applicationComponent.lockManager().isLocked());
} }
private void setTheme(Context ctx, SharedPreferences prefs) { private void setTheme(Context ctx, SharedPreferences prefs) {

View File

@@ -6,12 +6,16 @@ import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.android.AndroidNotificationManager;
import java.util.Locale; import java.util.Locale;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import androidx.core.text.TextUtilsCompat;
import static android.os.Build.VERSION.SDK_INT; import static android.os.Build.VERSION.SDK_INT;
import static androidx.core.view.ViewCompat.LAYOUT_DIRECTION_LTR;
import static org.briarproject.briar.android.settings.SettingsFragment.LANGUAGE; import static org.briarproject.briar.android.settings.SettingsFragment.LANGUAGE;
@NotNullByDefault @NotNullByDefault
@@ -21,6 +25,7 @@ public class Localizer {
@Nullable @Nullable
private static Localizer INSTANCE; private static Localizer INSTANCE;
private final Locale systemLocale; private final Locale systemLocale;
@Nullable
private final Locale locale; private final Locale locale;
private Localizer(SharedPreferences sharedPreferences) { private Localizer(SharedPreferences sharedPreferences) {
@@ -30,10 +35,17 @@ public class Localizer {
private Localizer(Locale systemLocale, @Nullable Locale userLocale) { private Localizer(Locale systemLocale, @Nullable Locale userLocale) {
this.systemLocale = systemLocale; this.systemLocale = systemLocale;
if (userLocale == null) locale = systemLocale; locale = userLocale;
else locale = userLocale; setLocaleAndSystemConfiguration(locale);
} }
private Localizer(Locale systemLocale) {
this.systemLocale = systemLocale;
locale = null;
setLocaleAndSystemConfiguration(systemLocale);
}
// Instantiate the Localizer. // Instantiate the Localizer.
public static synchronized void initialize(SharedPreferences prefs) { public static synchronized void initialize(SharedPreferences prefs) {
if (INSTANCE == null) if (INSTANCE == null)
@@ -41,9 +53,11 @@ public class Localizer {
} }
// Reinstantiate the Localizer with the system locale // Reinstantiate the Localizer with the system locale
public static synchronized void reinitialize() { public static synchronized void reinitialize(Context appContext) {
if (INSTANCE != null) if (INSTANCE != null && INSTANCE.locale != null) {
INSTANCE = new Localizer(INSTANCE.systemLocale, null); INSTANCE = new Localizer(INSTANCE.systemLocale);
INSTANCE.forceLocale(appContext, INSTANCE.systemLocale);
}
} }
// Get the current instance. // Get the current instance.
@@ -64,29 +78,98 @@ public class Localizer {
if (tag.contains("-")) { if (tag.contains("-")) {
String[] langArray = tag.split("-"); String[] langArray = tag.split("-");
return new Locale(langArray[0], langArray[1]); return new Locale(langArray[0], langArray[1]);
} else } else {
return new Locale(tag); return new Locale(tag);
} }
}
// Returns the localized version of context // Returns the localized version of context
public Context setLocale(Context context) { public Context setLocale(Context context) {
if (locale == null || SDK_INT < 17) return context;
Resources res = context.getResources(); Resources res = context.getResources();
Configuration conf = res.getConfiguration(); Configuration conf = res.getConfiguration();
Locale currentLocale; updateConfiguration(conf, locale);
if (SDK_INT >= 24) { return context.createConfigurationContext(conf);
currentLocale = conf.getLocales().get(0); }
} else
currentLocale = conf.locale; // For API < 17 only.
if (locale.equals(currentLocale)) public void setLocaleLegacy(Context appContext) {
return context; if (SDK_INT >= 17 || locale == null) return;
Locale.setDefault(locale); forceLocale(appContext, locale);
}
// Forces the update of the resources through the deprecated API.
private void forceLocale(Context context, Locale locale) {
Resources res = context.getResources();
Configuration conf = res.getConfiguration();
updateConfiguration(conf, locale);
res.updateConfiguration(conf, res.getDisplayMetrics());
}
private void updateConfiguration(Configuration conf, Locale locale) {
if (SDK_INT >= 17) { if (SDK_INT >= 17) {
conf.setLocale(locale); conf.setLocale(locale);
context.createConfigurationContext(conf); } else {
} else
conf.locale = locale; conf.locale = locale;
}
}
private void setLocaleAndSystemConfiguration(@Nullable Locale locale) {
if (locale == null) return;
Locale.setDefault(locale);
if (SDK_INT >= 23) return;
Resources systemResources = Resources.getSystem();
Configuration systemConfiguration = systemResources.getConfiguration();
updateConfiguration(systemConfiguration, locale);
// DateUtils uses the system resources, so we need to update them too.
//noinspection deprecation //noinspection deprecation
res.updateConfiguration(conf, res.getDisplayMetrics()); systemResources.updateConfiguration(systemConfiguration,
return context; systemResources.getDisplayMetrics());
}
private Locale getLocaleFromConfig(Configuration config) {
if (SDK_INT >= 24) {
return config.getLocales().get(0);
} else {
//noinspection deprecation
return config.locale;
} }
} }
public void applicationConfigurationChanged(Context appContext,
Configuration newConfig,
AndroidNotificationManager androidNotificationManager,
boolean locked) {
Locale newLocale = getLocaleFromConfig(newConfig);
if (locale == null && newLocale != systemLocale) {
androidNotificationManager.restartNotifications(locked, false);
}
if (newLocale == locale) return;
setLocaleAndSystemConfiguration(locale);
if (SDK_INT < 17) setLocaleLegacy(appContext);
}
/**
* Indicates whether the language represented by locale
* should be offered to the user on this device.
* * Android doesn't pick up Asturian on API < 21
* * RTL languages are supported since API >= 17
*/
public static boolean isLocaleSupported(Locale locale) {
if (SDK_INT >= 21) return true;
if (locale.getLanguage().equals("ast")) return false;
if (SDK_INT >= 17) return true;
return isLeftToRight(locale);
}
// Exclude RTL locales on API < 17, they won't be laid out correctly
private static boolean isLeftToRight(Locale locale) {
// TextUtilsCompat returns the wrong direction for Hebrew on some phones
String language = locale.getLanguage();
if (language.equals("iw") || language.equals("he")) return false;
int direction =
TextUtilsCompat.getLayoutDirectionFromLocale(locale);
return direction == LAYOUT_DIRECTION_LTR;
}
}

View File

@@ -44,7 +44,6 @@ import javax.inject.Inject;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.StringRes; import androidx.annotation.StringRes;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.text.TextUtilsCompat;
import androidx.preference.ListPreference; import androidx.preference.ListPreference;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceChangeListener; import androidx.preference.Preference.OnPreferenceChangeListener;
@@ -70,7 +69,6 @@ import static android.provider.Settings.EXTRA_APP_PACKAGE;
import static android.provider.Settings.EXTRA_CHANNEL_ID; import static android.provider.Settings.EXTRA_CHANNEL_ID;
import static android.provider.Settings.System.DEFAULT_NOTIFICATION_URI; import static android.provider.Settings.System.DEFAULT_NOTIFICATION_URI;
import static android.widget.Toast.LENGTH_SHORT; import static android.widget.Toast.LENGTH_SHORT;
import static androidx.core.view.ViewCompat.LAYOUT_DIRECTION_LTR;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
@@ -296,13 +294,20 @@ public class SettingsFragment extends PreferenceFragmentCompat
Locale locale = Localizer.getLocaleFromTag(tag); Locale locale = Localizer.getLocaleFromTag(tag);
if (locale == null) if (locale == null)
throw new IllegalStateException(); throw new IllegalStateException();
// Exclude RTL locales on API < 17, they won't be laid out correctly // Check if the locale is supported on this device
if (SDK_INT < 17 && !isLeftToRight(locale)) { if (!Localizer.isLocaleSupported(locale)) {
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Skipping RTL locale " + tag); LOG.info("Skipping unsupported locale " + tag);
continue; continue;
} }
String nativeName = locale.getDisplayName(locale); String nativeName;
// Unknown languages won't be translated to their native name.
if (locale.getLanguage().equals("ast")) {
nativeName = "Asturianu";
} else if (locale.getLanguage().equals("oc")) {
nativeName = "Occitan";
} else {
nativeName = locale.getDisplayName(locale);
// Fallback to English if the name is unknown in both native and // Fallback to English if the name is unknown in both native and
// current locale. // current locale.
if (nativeName.equals(tag)) { if (nativeName.equals(tag)) {
@@ -310,6 +315,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
if (!tmp.isEmpty() && !tmp.equals(nativeName)) if (!tmp.isEmpty() && !tmp.equals(nativeName))
nativeName = tmp; nativeName = tmp;
} }
}
// Prefix with LRM marker to prevent any RTL direction // Prefix with LRM marker to prevent any RTL direction
entries.add("\u200E" + nativeName.substring(0, 1).toUpperCase() entries.add("\u200E" + nativeName.substring(0, 1).toUpperCase()
+ nativeName.substring(1)); + nativeName.substring(1));
@@ -319,13 +325,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
language.setEntryValues(entryValues.toArray(new CharSequence[0])); language.setEntryValues(entryValues.toArray(new CharSequence[0]));
} }
private boolean isLeftToRight(Locale locale) {
// TextUtilsCompat returns the wrong direction for Hebrew on some phones
String language = locale.getLanguage();
if (language.equals("iw") || language.equals("he")) return false;
int direction = TextUtilsCompat.getLayoutDirectionFromLocale(locale);
return direction == LAYOUT_DIRECTION_LTR;
}
private void setTorNetworkSummary(int torNetworkSetting) { private void setTorNetworkSummary(int torNetworkSetting) {
if (torNetworkSetting != PREF_TOR_NETWORK_AUTOMATIC) { if (torNetworkSetting != PREF_TOR_NETWORK_AUTOMATIC) {

View File

@@ -93,4 +93,7 @@ public interface AndroidNotificationManager {
void blockAllBlogPostNotifications(); void blockAllBlogPostNotifications();
void unblockAllBlogPostNotifications(); void unblockAllBlogPostNotifications();
void restartNotifications(boolean locked, boolean mayAlertAgain);
} }