I am creating an app that depending on which country your mobile network provider is from, displays a list of all alternative mobile network providers from that same country. To achieve this, I was retrieving the country code using telephonyManager.getSimCountryIso().
Official android developer docs say : "Returns the ISO country code equivalent for the SIM provider's country code", so from this I was expecting country code will always be always the same independently from device location. But thats not how it actually works! For example I recently experienced this case: I have an android device with SIM card from Spain belonging to a spanish network provider. So if I am in Spain telephonyManager.getSimCountryIso() returns "es". Everything working fine to that point. The problem is when I travel to France for example I debug the app and find out the telephonyManager.getSimCountryIso() is returning country code: "nl" (from Netherlands!? and I am in France in roaming but with the same spanish SIM card!). I am using the same device and the same SIM card than in Spain so country code ISO should still be "es".
My question is How does this method actually work? why am I getting country code "nl" ( Netherlands) if I am using a spanish SIM card?
Thanks in advance for any help
You can use MCC MNC to get SIM country, it is SIM configured and has nothing to do with the network you are on.
Configuration config = getResources().getConfiguration();
int countryCode = config.mcc;
You can find MCC list here MccTable.java
For example Spain is 214 and France is 208
MCC should work on all GSM devices with SIM card but it is unreliable on CDMA networks
For CDMA devices I found the following solution
if (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
Class<?> c = Class.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.class);
// Gives MCC + MNC
String homeOperator = ((String) get.invoke(c, "ro.cdma.home.operator.numeric"));
String country = homeOperator.substring(0, 3); // the last three digits is MNC
} else {
Configuration config = getResources().getConfiguration();
int countryCode = config.mcc;
}
You can try to get country code from TelephonyManager (from SIM or CDMA devices), and if not available try to get it from local configuration. Here is a complete example.
private static String getDeviceCountryCode(Context context) {
String countryCode;
// try to get country code from TelephonyManager service
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if(tm != null) {
// query first getSimCountryIso()
countryCode = tm.getSimCountryIso();
if (countryCode != null && countryCode.length() == 2)
return countryCode.toLowerCase();
if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
// special case for CDMA Devices
countryCode = getCDMACountryIso();
} else {
// for 3G devices (with SIM) query getNetworkCountryIso()
countryCode = tm.getNetworkCountryIso();
}
if (countryCode != null && countryCode.length() == 2)
return countryCode.toLowerCase();
}
// if network country not available (tablets maybe), get country code from Locale class
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
countryCode = context.getResources().getConfiguration().getLocales().get(0).getCountry();
} else {
countryCode = context.getResources().getConfiguration().locale.getCountry();
}
if (countryCode != null && countryCode.length() == 2)
return countryCode.toLowerCase();
// general fallback to "us"
return "us";
}
@SuppressLint("PrivateApi")
private static String getCDMACountryIso() {
try {
// try to get country code from SystemProperties private class
Class<?> systemProperties = Class.forName("android.os.SystemProperties");
Method get = systemProperties.getMethod("get", String.class);
// get homeOperator that contain MCC + MNC
String homeOperator = ((String) get.invoke(systemProperties,
"ro.cdma.home.operator.numeric"));
// first 3 chars (MCC) from homeOperator represents the country code
int mcc = Integer.parseInt(homeOperator.substring(0, 3));
// mapping just countries that actually use CDMA networks
switch (mcc) {
case 330: return "PR";
case 310: return "US";
case 311: return "US";
case 312: return "US";
case 316: return "US";
case 283: return "AM";
case 460: return "CN";
case 455: return "MO";
case 414: return "MM";
case 619: return "SL";
case 450: return "KR";
case 634: return "SD";
case 434: return "UZ";
case 232: return "AT";
case 204: return "NL";
case 262: return "DE";
case 247: return "LV";
case 255: return "UA";
}
} catch (ClassNotFoundException ignored) {
} catch (NoSuchMethodException ignored) {
} catch (IllegalAccessException ignored) {
} catch (InvocationTargetException ignored) {
} catch (NullPointerException ignored) {
}
return null;
}
Also another idea is to try an API request like in this answer, or to use fine location.
References here and here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With