package de.westnordost.streetcomplete.data.meta; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; import android.preference.PreferenceManager; import android.telephony.TelephonyManager; import java.io.InputStream; import java.util.List; import java.util.Locale; import javax.inject.Inject; import de.westnordost.streetcomplete.Prefs; import de.westnordost.streetcomplete.R; public class CurrentCountry { private final Context applicationContext; private LanguagesByCountry languagesByCountry; @Inject public CurrentCountry(Context applicationContext) { this.applicationContext = applicationContext; } private LanguagesByCountry getLanguagesByCountry() { if(languagesByCountry == null) { languagesByCountry = createLanguagesByCountry(); } return languagesByCountry; } private synchronized LanguagesByCountry createLanguagesByCountry() { // double check in synchronized block if(languagesByCountry != null) return languagesByCountry; InputStream is = applicationContext.getResources().openRawResource(R.raw.country_codes); return new LanguagesByCountry(is); } public Resources getResources() { Locale locale = getLocale(); Configuration configuration = getLocaleConfiguration(locale); return applicationContext.createConfigurationContext(configuration).getResources(); } private Configuration getLocaleConfiguration(Locale locale) { Configuration configuration = new Configuration(applicationContext.getResources().getConfiguration()); configuration.setLocale(locale); return configuration; } /** Find the locale of the country the user is in currently. */ public Locale getLocale() { // always fall back to default locale if the current country cannot be found Locale locale = Locale.getDefault(); String countryCode = findCurrentCountry(); if(countryCode != null) { List<String> languages = getLanguagesByCountry().get(countryCode); // #53: Android could also return an invalid or non-existing countryCode, we can't trust it here if(languages != null) { // for countries with several official languages, the chance is higher that the user is // in an area in which the language he set in his preferences is spoken than not if (languages.size() > 1 && languages.indexOf(locale.getLanguage()) != -1) { locale = new Locale(locale.getLanguage(), countryCode); } // otherwise, use the most common one else if (languages.size() > 0) { locale = new Locale(languages.get(0), countryCode); } } } return locale; } /** Find the country the user is in currently. Returns null if the country cannot be determined */ private String findCurrentCountry() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext); String lastCountry = prefs.getString(Prefs.CURRENT_COUNTRY, null); String networkCountry = getTelephonyNetworkCountry(); // note: the telephony stuff will only work for mobile phones, not for tablets without SIM // card. Perhaps additionally use geocoding by last position here ... String currentCountry; if(networkCountry != null) { currentCountry = networkCountry; } else if(lastCountry != null) { currentCountry = lastCountry; } else { // fallback: if the user is not connected to a mobile network, the chance is high that // he is in the country where he bought the SIM card currentCountry = getTelephonySimCountry(); } if(currentCountry != null && !currentCountry.equals(lastCountry)) { SharedPreferences.Editor editor = prefs.edit(); editor.putString(Prefs.CURRENT_COUNTRY, currentCountry); editor.apply(); } return currentCountry; } private String getTelephonyNetworkCountry() { TelephonyManager tm = getTelephonyManager(); if(tm == null) return null; // is documented to be unreliable if(tm.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) return null; String networkCountry = tm.getNetworkCountryIso(); if(networkCountry == null || networkCountry.isEmpty()) return null; return networkCountry.toUpperCase(Locale.US); } private String getTelephonySimCountry() { TelephonyManager tm = getTelephonyManager(); if(tm == null) return null; String userCountry = tm.getSimCountryIso(); if (userCountry == null || userCountry.isEmpty()) return null; return userCountry.toUpperCase(Locale.US); } private TelephonyManager getTelephonyManager() { return (TelephonyManager) applicationContext.getSystemService(Context.TELEPHONY_SERVICE); } }