/******************************************************************************* * * Messenger Android Frontend * (C) 2013-2016 Nikolai Kudashov * (C) 2017 Björn Petersen * Contact: r10s@b44t.com, http://b44t.com * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see http://www.gnu.org/licenses/ . * ******************************************************************************/ package com.b44t.messenger; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.res.Configuration; import android.text.format.DateFormat; import com.b44t.messenger.time.FastDateFormat; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Locale; import java.util.TimeZone; public class LocaleController { public static boolean isRTL = false; public static int nameDisplayOrder = 1; private static boolean is24HourFormat = false; public FastDateFormat formatterDay; public FastDateFormat formatterWeek; public FastDateFormat formatterMonth; public FastDateFormat formatterYear; public FastDateFormat formatterMonthYear; public FastDateFormat chatDate; public FastDateFormat chatFullDate; private Locale currentLocale; private Locale systemDefaultLocale; // this is not Locale.getDefault(); Locale.getDefault() may be changed using Locale.setDefault() private LocaleInfo currentLocaleInfo; private String languageOverride; private boolean changingConfiguration = false; private class TimeZoneChangedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { ApplicationLoader.applicationHandler.post(new Runnable() { @Override public void run() { if (!formatterMonth.getTimeZone().equals(TimeZone.getDefault())) { LocaleController.getInstance().recreateFormatters(); } } }); } } public static class LocaleInfo { public String name; public String nameEnglish; public String shortName; } public HashMap languagesDict = new HashMap<>(); private static volatile LocaleController Instance = null; public static LocaleController getInstance() { LocaleController localInstance = Instance; if (localInstance == null) { synchronized (LocaleController.class) { localInstance = Instance; if (localInstance == null) { Instance = localInstance = new LocaleController(); } } } return localInstance; } public LocaleController() { LocaleInfo localeInfo = new LocaleInfo(); localeInfo.name = "English"; localeInfo.nameEnglish = "English"; localeInfo.shortName = "en"; languagesDict.put(localeInfo.shortName, localeInfo); localeInfo = new LocaleInfo(); localeInfo.name = "Italiano"; localeInfo.nameEnglish = "Italian"; localeInfo.shortName = "it"; languagesDict.put(localeInfo.shortName, localeInfo); localeInfo = new LocaleInfo(); localeInfo.name = "Español"; localeInfo.nameEnglish = "Spanish"; localeInfo.shortName = "es"; languagesDict.put(localeInfo.shortName, localeInfo); localeInfo = new LocaleInfo(); localeInfo.name = "Deutsch"; localeInfo.nameEnglish = "German"; localeInfo.shortName = "de"; languagesDict.put(localeInfo.shortName, localeInfo); localeInfo = new LocaleInfo(); localeInfo.name = "Français"; localeInfo.nameEnglish = "French"; localeInfo.shortName = "fr"; languagesDict.put(localeInfo.shortName, localeInfo); localeInfo = new LocaleInfo(); localeInfo.name = "Nederlands"; localeInfo.nameEnglish = "Dutch"; localeInfo.shortName = "nl"; languagesDict.put(localeInfo.shortName, localeInfo); localeInfo = new LocaleInfo(); localeInfo.name = "Polski"; localeInfo.nameEnglish = "Polish"; localeInfo.shortName = "pl"; languagesDict.put(localeInfo.shortName, localeInfo); localeInfo = new LocaleInfo(); localeInfo.name = "Português"; localeInfo.nameEnglish = "Portuguese"; localeInfo.shortName = "pt"; languagesDict.put(localeInfo.shortName, localeInfo); localeInfo = new LocaleInfo(); localeInfo.name = "한국어"; localeInfo.nameEnglish = "Korean"; localeInfo.shortName = "ko"; languagesDict.put(localeInfo.shortName, localeInfo); localeInfo = new LocaleInfo(); localeInfo.name = "Magyar"; localeInfo.nameEnglish = "Hungarian"; localeInfo.shortName = "hu"; languagesDict.put(localeInfo.shortName, localeInfo); localeInfo = new LocaleInfo(); localeInfo.name = "Русский"; localeInfo.nameEnglish = "Russian"; localeInfo.shortName = "ru"; languagesDict.put(localeInfo.shortName, localeInfo); systemDefaultLocale = Locale.getDefault(); // we have to remember this as we may switch back to default later is24HourFormat = DateFormat.is24HourFormat(ApplicationLoader.applicationContext); LocaleInfo currentInfo = null; boolean override = false; try { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); String lang = preferences.getString("language", null); if (lang != null) { currentInfo = languagesDict.get(lang); if (currentInfo != null) { override = true; } } if (currentInfo == null && systemDefaultLocale.getLanguage() != null) { currentInfo = languagesDict.get(systemDefaultLocale.getLanguage()); } if (currentInfo == null) { currentInfo = languagesDict.get(getLocaleString(systemDefaultLocale)); } if (currentInfo == null) { currentInfo = languagesDict.get("en"); } applyLanguage(currentInfo, override); } catch (Exception e) { } try { IntentFilter timezoneFilter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED); ApplicationLoader.applicationContext.registerReceiver(new TimeZoneChangedReceiver(), timezoneFilter); } catch (Exception e) { } } private String getLocaleString(Locale locale) { if (locale == null) { return "en"; } String languageCode = locale.getLanguage(); String countryCode = locale.getCountry(); String variantCode = locale.getVariant(); if (languageCode.length() == 0 && countryCode.length() == 0) { return "en"; } StringBuilder result = new StringBuilder(11); result.append(languageCode); if (countryCode.length() > 0 || variantCode.length() > 0) { result.append('_'); } result.append(countryCode); if (variantCode.length() > 0) { result.append('_'); } result.append(variantCode); return result.toString(); } public void applyLanguage(LocaleInfo localeInfo, boolean override) { if (localeInfo == null) { return; } try { Locale newLocale; if (localeInfo.shortName != null) { String[] args = localeInfo.shortName.split("_"); if (args.length == 1) { newLocale = new Locale(localeInfo.shortName); } else { newLocale = new Locale(args[0], args[1]); } if (newLocale != null) { if (override) { languageOverride = localeInfo.shortName; SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); editor.putString("language", localeInfo.shortName); editor.apply(); } } } else { newLocale = systemDefaultLocale; // this is not Locale.getDefault(); Locale.getDefault() may be changed using Locale.setDefault() languageOverride = null; SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); editor.remove("language"); editor.apply(); if (newLocale != null) { LocaleInfo info = null; if (newLocale.getLanguage() != null) { info = languagesDict.get(newLocale.getLanguage()); } if (info == null) { info = languagesDict.get(getLocaleString(newLocale)); } if (info == null) { newLocale = Locale.US; } } } if (newLocale != null) { currentLocale = newLocale; currentLocaleInfo = localeInfo; changingConfiguration = true; Locale.setDefault(currentLocale); android.content.res.Configuration config = new android.content.res.Configuration(); config.locale = currentLocale; ApplicationLoader.applicationContext.getResources().updateConfiguration(config, ApplicationLoader.applicationContext.getResources().getDisplayMetrics()); changingConfiguration = false; } } catch (Exception e) { changingConfiguration = false; } recreateFormatters(); } public void rebuildUiParts() { KeepAliveService kas = KeepAliveService.getInstance(); if( kas != null ) { kas.updateForegroundNotification(); } } public static String getCurrentLanguageName() { return getString("LanguageName", R.string.LanguageName); } private String getStringInternal(String key, int res) { String value = null; try { value = ApplicationLoader.applicationContext.getString(res); } catch (Exception e) { } if (value == null) { value = "LOC_ERR:" + key; } return value; } public static String getString(String key, int res) { return getInstance().getStringInternal(key, res); } public static String formatString(String key, int res, Object... args) { try { String value = ApplicationLoader.applicationContext.getString(res); if (getInstance().currentLocale != null) { return String.format(getInstance().currentLocale, value, args); } else { return String.format(value, args); } } catch (Exception e) { return "LOC_ERR: " + key; } } public static String formatStringSimple(String string, Object... args) { try { if (getInstance().currentLocale != null) { return String.format(getInstance().currentLocale, string, args); } else { return String.format(string, args); } } catch (Exception e) { return "LOC_ERR: " + string; } } public void onDeviceConfigurationChange(Configuration newConfig) { if (changingConfiguration) { return; } is24HourFormat = DateFormat.is24HourFormat(ApplicationLoader.applicationContext); systemDefaultLocale = newConfig.locale; if (languageOverride != null) { LocaleInfo toSet = currentLocaleInfo; currentLocaleInfo = null; applyLanguage(toSet, false); } else { Locale newLocale = newConfig.locale; if (newLocale != null) { String d1 = newLocale.getDisplayName(); String d2 = currentLocale.getDisplayName(); if (d1 != null && d2 != null && !d1.equals(d2)) { recreateFormatters(); } currentLocale = newLocale; } } rebuildUiParts(); } public static String formatDateChat(long date) { try { Calendar rightNow = Calendar.getInstance(); int year = rightNow.get(Calendar.YEAR); rightNow.setTimeInMillis(date * 1000); int dateYear = rightNow.get(Calendar.YEAR); if (year == dateYear) { return getInstance().chatDate.format(date * 1000); } return getInstance().chatFullDate.format(date * 1000); } catch (Exception e) { } return "LOC_ERR: formatDateChat"; } private FastDateFormat createFormatter(Locale locale, String format, String defaultFormat) { if (format == null || format.length() == 0) { format = defaultFormat; } FastDateFormat formatter; try { formatter = FastDateFormat.getInstance(format, locale); } catch (Exception e) { format = defaultFormat; formatter = FastDateFormat.getInstance(format, locale); } return formatter; } private void recreateFormatters() { Locale locale = currentLocale; if (locale == null) { locale = Locale.getDefault(); } String lang = locale.getLanguage(); if (lang == null) { lang = "en"; } isRTL = lang.toLowerCase().equals("ar"); nameDisplayOrder = lang.toLowerCase().equals("ko") ? 2 : 1; formatterMonth = createFormatter(locale, getStringInternal("formatterMonth", R.string.formatterMonth), "dd MMM"); formatterYear = createFormatter(locale, getStringInternal("formatterYear", R.string.formatterYear), "dd.MM.yyyy"); chatDate = createFormatter(locale, getStringInternal("chatDate", R.string.chatDate), "d MMMM"); chatFullDate = createFormatter(locale, getStringInternal("chatFullDate", R.string.chatFullDate), "d MMMM yyyy"); formatterWeek = createFormatter(locale, getStringInternal("formatterWeek", R.string.formatterWeek), "EEE"); formatterMonthYear = createFormatter(locale, getStringInternal("formatterMonthYear", R.string.formatterMonthYear), "MMMM yyyy"); formatterDay = createFormatter(lang.toLowerCase().equals("ar") || lang.toLowerCase().equals("ko") ? locale : Locale.US, is24HourFormat ? getStringInternal("formatterDay24H", R.string.formatterDay24H) : getStringInternal("formatterDay12H", R.string.formatterDay12H), is24HourFormat ? "HH:mm" : "h:mm a"); } public static String stringForMessageListDate(long date) { try { Calendar rightNow = Calendar.getInstance(); int day = rightNow.get(Calendar.DAY_OF_YEAR); int year = rightNow.get(Calendar.YEAR); rightNow.setTimeInMillis(date * 1000); int dateDay = rightNow.get(Calendar.DAY_OF_YEAR); int dateYear = rightNow.get(Calendar.YEAR); if (year != dateYear) { return getInstance().formatterYear.format(new Date(date * 1000)); } else { int dayDiff = dateDay - day; if(dayDiff == 0 || dayDiff == -1 && (int)(System.currentTimeMillis() / 1000) - date < 60 * 60 * 8) { return getInstance().formatterDay.format(new Date(date * 1000)); } else if(dayDiff > -7 && dayDiff <= -1) { return getInstance().formatterWeek.format(new Date(date * 1000)); } else { return getInstance().formatterMonth.format(new Date(date * 1000)); } } } catch (Exception e) { } return "LOC_ERR"; } }