From 75e910e1d910b79784e53a2885b78763e7c0128f Mon Sep 17 00:00:00 2001 From: goapunk Date: Tue, 15 May 2018 19:03:25 +0200 Subject: [PATCH 1/6] Add a language setting --- briar-android/build.gradle | 31 +++++++ .../briar/android/BriarApplicationImpl.java | 12 ++- .../briar/android/BriarService.java | 5 ++ .../briarproject/briar/android/Localizer.java | 85 ++++++++++++++++++ .../briar/android/activity/BaseActivity.java | 8 ++ .../android/navdrawer/NavDrawerActivity.java | 15 ++-- .../android/settings/SettingsActivity.java | 1 - .../android/settings/SettingsFragment.java | 86 ++++++++++++++++--- briar-android/src/main/res/values/arrays.xml | 34 +++++++- briar-android/src/main/res/values/strings.xml | 6 ++ briar-android/src/main/res/xml/settings.xml | 11 +++ .../briar/android/TestBriarApplication.java | 1 + 12 files changed, 276 insertions(+), 19 deletions(-) create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/Localizer.java diff --git a/briar-android/build.gradle b/briar-android/build.gradle index 839eab3ef..2a5d6b97b 100644 --- a/briar-android/build.gradle +++ b/briar-android/build.gradle @@ -284,3 +284,34 @@ android { warning 'ExtraTranslation' } } + +task verifyTranslations { + doLast { + def file = "briar-android/src/main/res/values/arrays.xml" + def arrays = new XmlParser().parse(file) + def lc = arrays.children().find { it.@name == "pref_language_values" } + def translations = [] + lc.children().each { value -> translations.add(value.text()) } + + def folders = ["default", "en-US"] + new File("briar-android/src/main/res").eachDir { dir -> + if (dir.name.startsWith("values-")) { + folders.add(dir.name.substring(7).replace("-r", "-")) + } + } + folders.each { n -> + if (!translations.remove(n)) { + throw new GradleException("Translation " + n + " is missing in $file") + } + } + if (translations.size() != 0) + throw new GradleException("Translations\n" + translations.join("\n") + + "\nhave no matching value folder") + } +} + +project.afterEvaluate { + preBuild.dependsOn.add(verifyTranslations) +} + + diff --git a/briar-android/src/main/java/org/briarproject/briar/android/BriarApplicationImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/BriarApplicationImpl.java index 97e19062a..7b7e35846 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/BriarApplicationImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/BriarApplicationImpl.java @@ -2,6 +2,7 @@ package org.briarproject.briar.android; import android.app.Application; import android.content.Context; +import android.content.res.Configuration; import android.os.StrictMode; import android.os.StrictMode.ThreadPolicy; import android.os.StrictMode.VmPolicy; @@ -75,7 +76,10 @@ public class BriarApplicationImpl extends Application @Override protected void attachBaseContext(Context base) { - super.attachBaseContext(base); + // Loading the language needs to be done here. + Localizer.initialize(base); + super.attachBaseContext( + Localizer.getInstance().setLocale(base)); ACRA.init(this); } @@ -108,6 +112,12 @@ public class BriarApplicationImpl extends Application AndroidEagerSingletons.initEagerSingletons(applicationComponent); } + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + Localizer.getInstance().setLocale(this); + } + private void enableStrictMode() { ThreadPolicy.Builder threadPolicy = new ThreadPolicy.Builder(); threadPolicy.detectAll(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java b/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java index f3cc72c5b..b6aaad4b9 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java @@ -168,6 +168,11 @@ public class BriarService extends Service { registerReceiver(receiver, filter); } + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext(Localizer.getInstance().setLocale(base)); + } + private void showStartupFailureNotification(StartResult result) { androidExecutor.runOnUiThread(() -> { NotificationCompat.Builder b = new NotificationCompat.Builder( diff --git a/briar-android/src/main/java/org/briarproject/briar/android/Localizer.java b/briar-android/src/main/java/org/briarproject/briar/android/Localizer.java new file mode 100644 index 000000000..c734f13f0 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/Localizer.java @@ -0,0 +1,85 @@ +package org.briarproject.briar.android; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.preference.PreferenceManager; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.util.Locale; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import static android.os.Build.VERSION.SDK_INT; +import static org.briarproject.briar.android.settings.SettingsFragment.LANGUAGE; + +@NotNullByDefault +public class Localizer { + + private static Localizer INSTANCE; + @Nullable + private final Locale locale; + private final SharedPreferences sharedPreferences; + + private Localizer(Context context) { + sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + locale = getLocaleFromTag( + sharedPreferences.getString(LANGUAGE, "default")); + } + + public static synchronized void initialize(Context context) { + if (INSTANCE == null) + INSTANCE = new Localizer(context); + } + + public static synchronized Localizer getInstance() { + if (INSTANCE == null) + throw new IllegalStateException("Localizer not initialized"); + return INSTANCE; + } + + public SharedPreferences getSharedPreferences() { + return sharedPreferences; + } + + // Get Locale from BCP-47 tag + @Nullable + public static Locale getLocaleFromTag(String tag) { + if (tag.equals("default")) + return null; + if (SDK_INT >= 21) { + return Locale.forLanguageTag(tag); + } + if (tag.contains("-")) { + String[] langArray = tag.split("-"); + return new Locale(langArray[0], langArray[1]); + } else + return new Locale(tag); + } + + public Context setLocale(Context context) { + if (locale == null) + return context; + Resources res = context.getResources(); + Configuration conf = res.getConfiguration(); + Locale currentLocale; + if (SDK_INT >= 24) { + currentLocale = conf.getLocales().get(0); + } else + currentLocale = conf.locale; + if (locale.equals(currentLocale)) + return context; + Locale.setDefault(locale); + if (SDK_INT >= 17) { + conf.setLocale(locale); + context.createConfigurationContext(conf); + } else + conf.locale = locale; + //noinspection deprecation + res.updateConfiguration(conf, res.getDisplayMetrics()); + return context; + } +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java index 7c8f5061a..c693ccbfc 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java @@ -1,5 +1,6 @@ package org.briarproject.briar.android.activity; +import android.content.Context; import android.os.Bundle; import android.os.IBinder; import android.support.annotation.LayoutRes; @@ -18,6 +19,7 @@ import org.briarproject.briar.R; import org.briarproject.briar.android.AndroidComponent; import org.briarproject.briar.android.BriarApplication; import org.briarproject.briar.android.DestroyableContext; +import org.briarproject.briar.android.Localizer; import org.briarproject.briar.android.controller.ActivityLifecycleController; import org.briarproject.briar.android.forum.ForumModule; import org.briarproject.briar.android.fragment.BaseFragment; @@ -84,6 +86,12 @@ public abstract class BaseActivity extends AppCompatActivity } } + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext( + Localizer.getInstance().setLocale(base)); + } + public ActivityComponent getActivityComponent() { return activityComponent; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerActivity.java index af09db700..e7800f1db 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerActivity.java @@ -68,6 +68,7 @@ public class NavDrawerActivity extends BriarActivity implements public static final String INTENT_GROUPS = "intent_groups"; public static final String INTENT_FORUMS = "intent_forums"; public static final String INTENT_BLOGS = "intent_blogs"; + public static final String INTENT_SIGN_OUT = "intent_sign_out"; private static final Logger LOG = Logger.getLogger(NavDrawerActivity.class.getName()); @@ -99,6 +100,8 @@ public class NavDrawerActivity extends BriarActivity implements R.id.nav_btn_contacts); } else if (intent.getBooleanExtra(INTENT_BLOGS, false)) { startFragment(FeedFragment.newInstance(), R.id.nav_btn_blogs); + } else if (intent.getBooleanExtra(INTENT_SIGN_OUT, false)) { + signOut(false); } setIntent(null); } @@ -225,12 +228,12 @@ public class NavDrawerActivity extends BriarActivity implements finish(); } else if (fm.getBackStackEntryCount() == 0 && fm.findFragmentByTag(ContactListFragment.TAG) == null) { - /* - * This makes sure that the first fragment (ContactListFragment) the - * user sees is the same as the last fragment the user sees before - * exiting. This models the typical Google navigation behaviour such - * as in Gmail/Inbox. - */ + /* + * This makes sure that the first fragment (ContactListFragment) the + * user sees is the same as the last fragment the user sees before + * exiting. This models the typical Google navigation behaviour such + * as in Gmail/Inbox. + */ startFragment(ContactListFragment.newInstance(), R.id.nav_btn_contacts); } else { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsActivity.java index 37870a983..48b4b7fa9 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsActivity.java @@ -36,5 +36,4 @@ public class SettingsActivity extends BriarActivity { } return false; } - } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java index c69dd65de..f75ba97e3 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java @@ -1,8 +1,10 @@ package org.briarproject.briar.android.settings; import android.annotation.TargetApi; +import android.app.AlertDialog; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; @@ -30,8 +32,11 @@ import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent; import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.bramble.util.StringUtils; import org.briarproject.briar.R; +import org.briarproject.briar.android.Localizer; +import org.briarproject.briar.android.navdrawer.NavDrawerActivity; import org.briarproject.briar.android.util.UserFeedback; +import java.util.Locale; import java.util.logging.Logger; import javax.inject.Inject; @@ -58,6 +63,7 @@ import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK; import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_ALWAYS; import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_RINGTONE; +import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.INTENT_SIGN_OUT; import static org.briarproject.briar.api.android.AndroidNotificationManager.BLOG_CHANNEL_ID; import static org.briarproject.briar.api.android.AndroidNotificationManager.CONTACT_CHANNEL_ID; import static org.briarproject.briar.api.android.AndroidNotificationManager.FORUM_CHANNEL_ID; @@ -80,11 +86,13 @@ public class SettingsFragment extends PreferenceFragmentCompat public static final String SETTINGS_NAMESPACE = "android-ui"; public static final String BT_NAMESPACE = BluetoothConstants.ID.getString(); public static final String TOR_NAMESPACE = TorConstants.ID.getString(); + public static final String LANGUAGE = "pref_key_language"; private static final Logger LOG = Logger.getLogger(SettingsFragment.class.getName()); private SettingsActivity listener; + private ListPreference language; private ListPreference enableBluetooth; private ListPreference torNetwork; private CheckBoxPreference notifyPrivateMessages; @@ -119,6 +127,8 @@ public class SettingsFragment extends PreferenceFragmentCompat public void onCreatePreferences(Bundle bundle, String s) { addPreferencesFromResource(R.xml.settings); + language = (ListPreference) findPreference(LANGUAGE); + setLanguageEntries(); enableBluetooth = (ListPreference) findPreference("pref_key_bluetooth"); torNetwork = (ListPreference) findPreference("pref_key_tor_network"); notifyPrivateMessages = (CheckBoxPreference) findPreference( @@ -137,6 +147,7 @@ public class SettingsFragment extends PreferenceFragmentCompat setSettingsEnabled(false); + language.setOnPreferenceChangeListener(this); enableBluetooth.setOnPreferenceChangeListener(this); torNetwork.setOnPreferenceChangeListener(this); if (SDK_INT >= 21) { @@ -180,6 +191,33 @@ public class SettingsFragment extends PreferenceFragmentCompat eventBus.removeListener(this); } + private void setLanguageEntries() { + CharSequence[] tags = language.getEntryValues(); + CharSequence[] nativeNames = new CharSequence[tags.length]; + for (int i = 0; i < tags.length; i++) { + String tag = tags[i].toString(); + if (tag.equals("default")) { + nativeNames[i] = getString(R.string.pref_language_default); + continue; + } + Locale locale = Localizer.getLocaleFromTag(tag); + if (locale == null) + throw new IllegalStateException(); + String nativeName = locale.getDisplayLanguage(locale); + // Fallback to English if the name is unknown in both native and + // current locale. + if (nativeName.equals(tag)) { + String tmp = locale.getDisplayLanguage(Locale.ENGLISH); + if (!tmp.isEmpty() && !tmp.equals(nativeName)) + nativeName = tmp; + } + nativeNames[i] = + nativeName.substring(0, 1).toUpperCase() + + nativeName.substring(1); + } + language.setEntries(nativeNames); + } + private void loadSettings() { listener.runOnDbThread(() -> { try { @@ -312,41 +350,69 @@ public class SettingsFragment extends PreferenceFragmentCompat } @Override - public boolean onPreferenceChange(Preference preference, Object o) { - if (preference == enableBluetooth) { - boolean btSetting = Boolean.valueOf((String) o); + public boolean onPreferenceChange(Preference preference, Object newValue) { + if (preference == language) { + if (!language.getValue().equals(newValue)) + languageChanged((String) newValue); + return false; + } else if (preference == enableBluetooth) { + boolean btSetting = Boolean.valueOf((String) newValue); storeBluetoothSettings(btSetting); } else if (preference == torNetwork) { - int torSetting = Integer.valueOf((String) o); + int torSetting = Integer.valueOf((String) newValue); storeTorSettings(torSetting); } else if (preference == notifyPrivateMessages) { Settings s = new Settings(); - s.putBoolean(PREF_NOTIFY_PRIVATE, (Boolean) o); + s.putBoolean(PREF_NOTIFY_PRIVATE, (Boolean) newValue); storeSettings(s); } else if (preference == notifyGroupMessages) { Settings s = new Settings(); - s.putBoolean(PREF_NOTIFY_GROUP, (Boolean) o); + s.putBoolean(PREF_NOTIFY_GROUP, (Boolean) newValue); storeSettings(s); } else if (preference == notifyForumPosts) { Settings s = new Settings(); - s.putBoolean(PREF_NOTIFY_FORUM, (Boolean) o); + s.putBoolean(PREF_NOTIFY_FORUM, (Boolean) newValue); storeSettings(s); } else if (preference == notifyBlogPosts) { Settings s = new Settings(); - s.putBoolean(PREF_NOTIFY_BLOG, (Boolean) o); + s.putBoolean(PREF_NOTIFY_BLOG, (Boolean) newValue); storeSettings(s); } else if (preference == notifyVibration) { Settings s = new Settings(); - s.putBoolean(PREF_NOTIFY_VIBRATION, (Boolean) o); + s.putBoolean(PREF_NOTIFY_VIBRATION, (Boolean) newValue); storeSettings(s); } else if (preference == notifyLockscreen) { Settings s = new Settings(); - s.putBoolean(PREF_NOTIFY_LOCK_SCREEN, (Boolean) o); + s.putBoolean(PREF_NOTIFY_LOCK_SCREEN, (Boolean) newValue); storeSettings(s); } return true; } + private void languageChanged(String newValue) { + AlertDialog.Builder builder = + new AlertDialog.Builder(getActivity()); + builder.setTitle(R.string.pref_language_title); + builder.setMessage(R.string.pref_language_changed); + builder.setPositiveButton(R.string.sign_out_button, + (dialogInterface, i) -> { + language.setValue(newValue); + SharedPreferences prefs = + Localizer.getInstance().getSharedPreferences(); + prefs.edit().putString(LANGUAGE, newValue) + .commit(); + Intent intent = new Intent(getContext(), + NavDrawerActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + intent.putExtra(INTENT_SIGN_OUT, true); + getActivity().startActivity(intent); + getActivity().finish(); + }); + builder.setNegativeButton(R.string.cancel, null); + builder.setCancelable(false); + builder.show(); + } + private void storeTorSettings(int torSetting) { listener.runOnDbThread(() -> { try { diff --git a/briar-android/src/main/res/values/arrays.xml b/briar-android/src/main/res/values/arrays.xml index 3eea71ecd..6ce3f2425 100644 --- a/briar-android/src/main/res/values/arrays.xml +++ b/briar-android/src/main/res/values/arrays.xml @@ -18,4 +18,36 @@ 1 2 - \ No newline at end of file + + default + en-US + ast + bg + br + ca + cs + de + es + eu + fa + fi + fr + gl + he + hi + it + ja + ms + nb + nl + oc + pt-BR + ro + ru + sq + sr + sv + tr + zh-CN + + diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index 1306feae1..a0087bedd 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -421,4 +421,10 @@ Camera permission was not granted QR code Show QR code fullscreen + + + Language + This setting will take effect when you restart Briar. Please sign out and restart Briar. + System default + Display diff --git a/briar-android/src/main/res/xml/settings.xml b/briar-android/src/main/res/xml/settings.xml index 452815014..7b3181fa0 100644 --- a/briar-android/src/main/res/xml/settings.xml +++ b/briar-android/src/main/res/xml/settings.xml @@ -1,6 +1,17 @@ + + + + Date: Tue, 29 May 2018 16:07:16 +0200 Subject: [PATCH 2/6] fix review --- briar-android/build.gradle | 2 +- .../briar/android/BriarApplicationImpl.java | 6 +++++- .../org/briarproject/briar/android/Localizer.java | 12 ++++++------ .../briar/android/TestBriarApplication.java | 5 ++++- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/briar-android/build.gradle b/briar-android/build.gradle index 2a5d6b97b..2dd91ee02 100644 --- a/briar-android/build.gradle +++ b/briar-android/build.gradle @@ -295,7 +295,7 @@ task verifyTranslations { def folders = ["default", "en-US"] new File("briar-android/src/main/res").eachDir { dir -> - if (dir.name.startsWith("values-")) { + if (dir.name.startsWith("values-") && !dir.name.endsWith("night")) { folders.add(dir.name.substring(7).replace("-r", "-")) } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/BriarApplicationImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/BriarApplicationImpl.java index 7b7e35846..a2ff968a7 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/BriarApplicationImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/BriarApplicationImpl.java @@ -2,10 +2,12 @@ package org.briarproject.briar.android; import android.app.Application; import android.content.Context; +import android.content.SharedPreferences; import android.content.res.Configuration; import android.os.StrictMode; import android.os.StrictMode.ThreadPolicy; import android.os.StrictMode.VmPolicy; +import android.preference.PreferenceManager; import org.acra.ACRA; import org.acra.ReportingInteractionMode; @@ -76,8 +78,10 @@ public class BriarApplicationImpl extends Application @Override protected void attachBaseContext(Context base) { + SharedPreferences prefs = + PreferenceManager.getDefaultSharedPreferences(base); // Loading the language needs to be done here. - Localizer.initialize(base); + Localizer.initialize(prefs); super.attachBaseContext( Localizer.getInstance().setLocale(base)); ACRA.init(this); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/Localizer.java b/briar-android/src/main/java/org/briarproject/briar/android/Localizer.java index c734f13f0..fbdb7fe84 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/Localizer.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/Localizer.java @@ -4,14 +4,12 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; -import android.preference.PreferenceManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import java.util.Locale; import javax.annotation.Nullable; -import javax.annotation.ParametersAreNonnullByDefault; import static android.os.Build.VERSION.SDK_INT; import static org.briarproject.briar.android.settings.SettingsFragment.LANGUAGE; @@ -19,20 +17,22 @@ import static org.briarproject.briar.android.settings.SettingsFragment.LANGUAGE; @NotNullByDefault public class Localizer { + // Locking: class + @Nullable private static Localizer INSTANCE; @Nullable private final Locale locale; private final SharedPreferences sharedPreferences; - private Localizer(Context context) { - sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + private Localizer(SharedPreferences prefs) { + this.sharedPreferences = prefs; locale = getLocaleFromTag( sharedPreferences.getString(LANGUAGE, "default")); } - public static synchronized void initialize(Context context) { + public static synchronized void initialize(SharedPreferences prefs) { if (INSTANCE == null) - INSTANCE = new Localizer(context); + INSTANCE = new Localizer(prefs); } public static synchronized Localizer getInstance() { diff --git a/briar-android/src/test/java/org/briarproject/briar/android/TestBriarApplication.java b/briar-android/src/test/java/org/briarproject/briar/android/TestBriarApplication.java index 93433123b..ae086abf3 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/TestBriarApplication.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/TestBriarApplication.java @@ -1,6 +1,8 @@ package org.briarproject.briar.android; import android.app.Application; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; import org.briarproject.bramble.BrambleCoreModule; import org.briarproject.briar.BriarCoreModule; @@ -27,7 +29,8 @@ public class TestBriarApplication extends Application super.onCreate(); LOG.info("Created"); - Localizer.initialize(this); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + Localizer.initialize(prefs); applicationComponent = DaggerAndroidComponent.builder() .appModule(new AppModule(this)) .build(); From 1834146ad02cfa9c60ee053ea7f1115fddd3dfd0 Mon Sep 17 00:00:00 2001 From: goapunk Date: Wed, 30 May 2018 15:10:39 +0200 Subject: [PATCH 3/6] fix hebrew --- briar-android/.gitignore | 1 + briar-android/build.gradle | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/briar-android/.gitignore b/briar-android/.gitignore index 2efc20c36..4d702fcd8 100644 --- a/briar-android/.gitignore +++ b/briar-android/.gitignore @@ -4,3 +4,4 @@ build local.properties .settings src/main/assets/*.zip +src/main/res/values-iw diff --git a/briar-android/build.gradle b/briar-android/build.gradle index 2dd91ee02..ce80f5407 100644 --- a/briar-android/build.gradle +++ b/briar-android/build.gradle @@ -300,13 +300,25 @@ task verifyTranslations { } } folders.each { n -> - if (!translations.remove(n)) { + if (!translations.remove(n) && n != 'iw') { throw new GradleException("Translation " + n + " is missing in $file") } } if (translations.size() != 0) throw new GradleException("Translations\n" + translations.join("\n") + "\nhave no matching value folder") + + // Some devices use iw instead of he for hebrew + def hebrew_legacy = new File("briar-android/src/main/res/values-iw") + def hebrew = new File("briar-android/src/main/res/values-he") + // Copy values-he to values-iw + if (hebrew.exists()) { + hebrew_legacy.mkdir() + copy { + from 'src/main/res/values-he' + into 'src/main/res/values-iw' + } + } } } From 8bc28f99c12cdf485cb492b8e88c41d0613b2a2a Mon Sep 17 00:00:00 2001 From: goapunk Date: Thu, 7 Jun 2018 10:00:50 +0200 Subject: [PATCH 4/6] Improvements: * Force LTR by prefixing language names with the LRM marker * Add Polish * Cleanup --- .../java/org/briarproject/briar/android/Localizer.java | 8 +------- .../briar/android/settings/SettingsFragment.java | 8 ++------ briar-android/src/main/res/values/arrays.xml | 1 + 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/Localizer.java b/briar-android/src/main/java/org/briarproject/briar/android/Localizer.java index fbdb7fe84..3f305c3f9 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/Localizer.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/Localizer.java @@ -22,10 +22,8 @@ public class Localizer { private static Localizer INSTANCE; @Nullable private final Locale locale; - private final SharedPreferences sharedPreferences; - private Localizer(SharedPreferences prefs) { - this.sharedPreferences = prefs; + private Localizer(SharedPreferences sharedPreferences) { locale = getLocaleFromTag( sharedPreferences.getString(LANGUAGE, "default")); } @@ -41,10 +39,6 @@ public class Localizer { return INSTANCE; } - public SharedPreferences getSharedPreferences() { - return sharedPreferences; - } - // Get Locale from BCP-47 tag @Nullable public static Locale getLocaleFromTag(String tag) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java index f75ba97e3..e975690e9 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java @@ -4,7 +4,6 @@ import android.annotation.TargetApi; import android.app.AlertDialog; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; @@ -211,8 +210,9 @@ public class SettingsFragment extends PreferenceFragmentCompat if (!tmp.isEmpty() && !tmp.equals(nativeName)) nativeName = tmp; } + // Prefix with LRM marker to prevent any RTL direction nativeNames[i] = - nativeName.substring(0, 1).toUpperCase() + + "\u200E" + nativeName.substring(0, 1).toUpperCase() + nativeName.substring(1); } language.setEntries(nativeNames); @@ -397,10 +397,6 @@ public class SettingsFragment extends PreferenceFragmentCompat builder.setPositiveButton(R.string.sign_out_button, (dialogInterface, i) -> { language.setValue(newValue); - SharedPreferences prefs = - Localizer.getInstance().getSharedPreferences(); - prefs.edit().putString(LANGUAGE, newValue) - .commit(); Intent intent = new Intent(getContext(), NavDrawerActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); diff --git a/briar-android/src/main/res/values/arrays.xml b/briar-android/src/main/res/values/arrays.xml index 6ce3f2425..978c98698 100644 --- a/briar-android/src/main/res/values/arrays.xml +++ b/briar-android/src/main/res/values/arrays.xml @@ -41,6 +41,7 @@ nb nl oc + pl pt-BR ro ru From 18c41951155ddf5fa54bfbeb4e755266a0dd9b96 Mon Sep 17 00:00:00 2001 From: goapunk Date: Thu, 7 Jun 2018 11:42:31 +0200 Subject: [PATCH 5/6] fix region and title --- .../briar/android/settings/SettingsFragment.java | 2 +- briar-android/src/main/res/values/strings.xml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java index e975690e9..083d624bb 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java @@ -202,7 +202,7 @@ public class SettingsFragment extends PreferenceFragmentCompat Locale locale = Localizer.getLocaleFromTag(tag); if (locale == null) throw new IllegalStateException(); - String nativeName = locale.getDisplayLanguage(locale); + String nativeName = locale.getDisplayName(locale); // Fallback to English if the name is unknown in both native and // current locale. if (nativeName.equals(tag)) { diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index a0087bedd..877c40e1f 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -323,6 +323,12 @@ No RSS feeds to show\n\nTap the + icon to import a feed There was a problem loading your feeds. Please try again later. + + Language & region + This setting will take effect when you restart Briar. Please sign out and restart Briar. + System default + Display + Networks Connect via Bluetooth @@ -421,10 +427,4 @@ Camera permission was not granted QR code Show QR code fullscreen - - - Language - This setting will take effect when you restart Briar. Please sign out and restart Briar. - System default - Display From fa267d38afbdc7e0538992ca9ea61cfcbc3d75a9 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 8 Jun 2018 12:00:30 +0100 Subject: [PATCH 6/6] Filter out RTL languages on API < 17. --- .../android/settings/SettingsFragment.java | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java index 083d624bb..00546afd4 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java @@ -9,6 +9,7 @@ import android.media.RingtoneManager; import android.net.Uri; import android.os.Bundle; import android.support.annotation.StringRes; +import android.support.v4.text.TextUtilsCompat; import android.support.v7.preference.CheckBoxPreference; import android.support.v7.preference.ListPreference; import android.support.v7.preference.Preference; @@ -35,6 +36,8 @@ import org.briarproject.briar.android.Localizer; import org.briarproject.briar.android.navdrawer.NavDrawerActivity; import org.briarproject.briar.android.util.UserFeedback; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; import java.util.logging.Logger; @@ -54,6 +57,7 @@ import static android.provider.Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS; import static android.provider.Settings.EXTRA_APP_PACKAGE; import static android.provider.Settings.EXTRA_CHANNEL_ID; import static android.provider.Settings.System.DEFAULT_NOTIFICATION_URI; +import static android.support.v4.view.ViewCompat.LAYOUT_DIRECTION_LTR; import static android.widget.Toast.LENGTH_SHORT; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; @@ -192,16 +196,24 @@ public class SettingsFragment extends PreferenceFragmentCompat private void setLanguageEntries() { CharSequence[] tags = language.getEntryValues(); - CharSequence[] nativeNames = new CharSequence[tags.length]; - for (int i = 0; i < tags.length; i++) { - String tag = tags[i].toString(); + List entries = new ArrayList<>(tags.length); + List entryValues = new ArrayList<>(tags.length); + for (CharSequence cs : tags) { + String tag = cs.toString(); if (tag.equals("default")) { - nativeNames[i] = getString(R.string.pref_language_default); + entries.add(getString(R.string.pref_language_default)); + entryValues.add(tag); continue; } Locale locale = Localizer.getLocaleFromTag(tag); if (locale == null) throw new IllegalStateException(); + // Exclude RTL locales on API < 17, they won't be laid out correctly + if (SDK_INT < 17 && !isLeftToRight(locale)) { + if (LOG.isLoggable(INFO)) + LOG.info("Skipping RTL locale " + tag); + continue; + } String nativeName = locale.getDisplayName(locale); // Fallback to English if the name is unknown in both native and // current locale. @@ -211,11 +223,20 @@ public class SettingsFragment extends PreferenceFragmentCompat nativeName = tmp; } // Prefix with LRM marker to prevent any RTL direction - nativeNames[i] = - "\u200E" + nativeName.substring(0, 1).toUpperCase() + - nativeName.substring(1); + entries.add("\u200E" + nativeName.substring(0, 1).toUpperCase() + + nativeName.substring(1)); + entryValues.add(tag); } - language.setEntries(nativeNames); + language.setEntries(entries.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 loadSettings() {