57

What is the best way to get the country code?

As of now, I know two ways. One is to get by TelephonyManager and another by Locale. Which is another best and unique way to find the country code on Android? To be more specific if TelephonyManager is not available in device e.g. its a tablet with no telephony. We can not relay on Locale as user could be in different country.

Vishal Pawar
  • 4,324
  • 4
  • 28
  • 54

8 Answers8

36

There are always huge discussions about this, and I never understand why developers and companies go for the complex way. The language selected by the user, means the language he/she wants to see always in his/her phone. They don't intend to have apps in a different language than others or the system.

The choice is very straight forward: Use Locale (to get the language the user selected as preferred), or make your best to piss them off showing them information in a language they already said they don't want to see things in.

To get the country code use:

Locale.getDefault().getCountry();
Jose L Ugia
  • 5,960
  • 3
  • 23
  • 26
  • 2
    I already suggested in question that I can get it by Locale I wanted another unique way I got it & posted my answer – Vishal Pawar Sep 10 '12 at 06:29
  • Yeah, I understand that you already now about Locale because you suggested it. My answer was more regarding to an user and usability perspective. – Jose L Ugia Sep 10 '12 at 09:00
  • 34
    In India, for example, there is no possibility to select Hindi as the phone language, because it does not exist on the android rom. Most people in India, are forced to chose another locale, such as English (UK). In which case, your code will break. In addition, in some countries people actually chose to see everything in English, as localization has other issues (right to left languages mainly). Which is another scenario which breaks your code. – Guy Jun 17 '13 at 13:11
  • 1
    That won't work in many countries! (I think that it is hardcoded as EN us). That explains why there are some apps to change the locale (thing that an average user would never install) – DNax Nov 07 '13 at 16:03
  • This is far from foolproof as certain android phones are very limited in the Locale options they offer. Many users in, say, Ireland have their locale set as GB because the only options available to them are English (UK) and English (US). In these cases, checking the Locale object gives the wrong answer. – Neil Apr 28 '14 at 08:16
  • 1
    Usability of this solution: 0. I live in Spain but I want my phone to be in english, so I select ENGLISH as the locale. With this, Locale.getDefault().getCountry() gives USA, not Spain. This solution gives results that are not real. – Corbella Jan 16 '15 at 08:22
  • 2
    @JoseLUgia In addition to the points others made, your answer is valid only if the purpose of determining the country is to localise the UI in the appropriate language. There are other reasons for determining the country, like licensing. Or, say, I have an app that lets you invest in mutual funds in India. I don't care what language you prefer, but if you're not in India, I might want to warn you that the app lets you invest only in Indian mutual funds. So, the country determined from the locale isn't always right. – Kartick Vaddadi Aug 17 '16 at 13:36
14

Use:

TelephonyManager tm = (TelephonyManager)getSystemService(getApplicationContext().TELEPHONY_SERVICE);
String countryCode = tm.getNetworkCountryIso();

It is better than getSimCountryIso because getSimCountryIso depends on the operator to burn the country ISO into the SIM and it also supports CDMA networks.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Asaf Pinhassi
  • 15,177
  • 12
  • 106
  • 130
  • 2
    This works, but what if the user is using a wifi only device || not inserted a sim card?`Locale.getDefault().getCountry()` doesnt work for a lot people who set their default language to english. I could be in India, we usually set the device locale to en-GB, querying the country now returns GB. – Irshu May 02 '18 at 08:59
10

You can use this code to get ISO 2:

Locale.getDefault().getCountry()

And this to get ISO 3:

Locale.getDefault().getISO3Country()
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bach Vu
  • 2,298
  • 1
  • 15
  • 19
6

I solved it by IP Address. You can get the IP address of your phone. If you are using Wi-Fi then it will be the IP address of the Wi-Fi hotspot or IP address of your mobile service provider server, so from that IP address you can send to a web service or something to track the country of that IP address.

There are some sources (database) available if Internet which provides the country of IP address.

Here is the example http://whatismyipaddress.com/ip-lookup.

Vishal Pawar
  • 4,324
  • 4
  • 28
  • 54
6

I think the IP address is the best way because it will give you the country where the phone is at the moment.

If you do it by

Locale.getDefault().getCountry();

you get the country where the user select the country, so you can have selected England, and you can be in Spain and maybe you need to know where he/she is at the moment.

Example: imagine that your app can buy something only in England. The user is from Spain, but he/she is on holidays in England and he/she wants to buy your product ... if you use

Locale.getDefault().getCountry();

that user won't be able to buy your product, so the IP address is the best way I think.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
D4rWiNS
  • 2,585
  • 5
  • 32
  • 54
  • But this way the spanish user could register on a english VPN server and buy those things from all over the world. IP could be acceptable for localization reasons, but I'd exclude it for security ones. – Niki Romagnoli Jul 11 '17 at 13:06
4

There is an excellent article by Reto Meier: http://android-developers.blogspot.com/2011/06/deep-dive-into-location.html

It describes different techniques to get the location of an Android device, including source code.

Next, when you have the location, it's easy to get the country for it - you can use an online web-service or offline database.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
HitOdessit
  • 7,198
  • 4
  • 36
  • 59
2

It's very hard to find the country without GPS and Google Services (China). TelephonyManager won't work if there isn't any SIM card in your phone.

And Locale won't work if a user in China set his/her language as English (the country you will be getting will be US or UK).

If your app requires an Internet connection then there is an option. You could use this API called ip-api. Please go through their documentation first if you are planing to use this.

There are other APIs like this freegeoip API.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Sunil Sunny
  • 3,949
  • 4
  • 23
  • 53
-2

Here is a complete example. Try to get country code from TelephonyManager (from a SIM card or CDMA devices), and if not available, try to get it from the local configuration.

private static String getDeviceCountryCode(Context context) {
    String countryCode;

    // Try to get the country code from the 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 a SIM card), query getNetworkCountryIso()
            countryCode = tm.getNetworkCountryIso();
        }

        if (countryCode != null && countryCode.length() == 2)
            return countryCode.toLowerCase();
    }

    // If the network country is not available (tablets maybe), get the country code from the 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 three characters (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 are here and here.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
radu_paun
  • 1,940
  • 21
  • 25