Android - Contact from number with Country Code

When retrieving a mobile number from an incoming sms it has the country code appended to it. Now as the matching contact in the database may not include the country code to get the contact name I'm using:

public static String getContactName(String number, Context context) {

    try {

        Uri personUri = Uri.withAppendedPath(
            ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number.trim()));
        String selection = PhoneLookup.NUMBER + " LIKE %" + number.trim() + "%";
        Cursor cur = context.getContentResolver().query(personUri,
            new String[] {
            PhoneLookup.DISPLAY_NAME
        },
            selection, null, null);
        if (cur.moveToFirst()) {
            String str = cur.getString(cur.getColumnIndex(PhoneLookup.DISPLAY_NAME));
            cur.close();
            return str;
        }
    } catch (Exception e) {
        //e.printStackTrace();
        return number;
    }
    return number;
}

This works perfectly if I pass in an exact match or a partial match. However if I want to get the contact id I'm using this code:

public static Contact getContact(String number, ContentResolver contentResolver) {

    Contact contact = new Contact(-1, number);
    try {
        Uri personUri = Uri.withAppendedPath(ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI, Uri.encode(number));
        String selection = ContactsContract.CommonDataKinds.Phone.NUMBER + " LIKE '%" + number + "%'";
        Cursor cur = contentResolver.query(personUri,
            new String[] {
            ContactsContract.CommonDataKinds.Phone.CONTACT_ID, PhoneLookup.DISPLAY_NAME
        },
            selection, null, null);
        if (cur.moveToFirst()) {
            contact = new Contact(Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID))),
                cur.getString(cur.getColumnIndex(PhoneLookup.DISPLAY_NAME)));
        }
        cur.close();
    } catch (Exception e) {}
    return contact;
}

This works perfect if the number is an exact match but if it is not it returns nothing. I need this method to find the id of the contact where its number is saved as "01111111111" and the incoming number is "+441111111111". Although they are looking at different URI's the selection code is pretty much the same so I'm not sure why it doesn't work for the second.

Any ideas?

Answers


I am using this code for the same reuirement and it returns name by returning contactId from the same code your problem will be solved

public static String getContactDisplayNameByNumber(String number) {
    Uri uri = Uri.withAppendedPath(
            ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
            Uri.encode(number));
    String name = "?";

    ContentResolver contentResolver = context.getContentResolver();
    Cursor contactLookup = contentResolver.query(uri, new String[] {
            BaseColumns._ID, ContactsContract.PhoneLookup.DISPLAY_NAME },
            null, null, null);

    try {
        if (contactLookup != null && contactLookup.getCount() > 0) {
            contactLookup.moveToNext();
            name = contactLookup.getString(contactLookup
                    .getColumnIndex(ContactsContract.Data.DISPLAY_NAME));
            // String contactId =
            // contactLookup.getString(contactLookup.getColumnIndex(BaseColumns._ID));
        }
    } finally {
        if (contactLookup != null) {
            contactLookup.close();
        }
    }

    return name;
}

I had a same problem last month and I managed to solve it using the google's libphonenumber library.

The problem only occurs with local/national phone numbers as they can be saved without country code or using '0'.

For example :

A typical phone number in India can be saved in following formats

  a. +919665123456
  b. 919665123456
  c. 09665123456
  d. 9665123456

and each of the above are perfectly valid formats to dial in India only

But in case if the phone numbers which belong to other than your native country it has to be saved compulsory with Country Code or you won't be able to make a call.

ex. 

 a. +1732-757-2923    (US)
 b. +97433-456-789    (Qatar)

So, the problem of matching contacts really occurs if the concerning contact is local/national.

And that's where libphonenumber comes into the picture. Using the library we can extract the phone number in actual national format belonging to that particular country.

Here's the trick. First pass the received number from sms as it is to the uri for matching in database. If it doesn't matches then extract the nationalized phone number using libphonenumber and then again pass it as uri for matching. (Uri.encode(number))

It worked in my case.

I've used it in the following way.

public String getContactDisplayNameByNumber(String number) {

    if (number != null && number.length() != 0) {

        String name = lookupNumber(number);

        if (!name.contains(number))
            return name;
        else {

            TelephonyManager manager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

            String usersCountryISOCode = manager.getNetworkCountryIso();

            PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
            try {
                PhoneNumber phonenUmber = phoneUtil.parse(name,
                        usersCountryISOCode);
                if (phoneUtil.isValidNumber(phonenUmber)) {
                    temp = phoneUtil
                            .getNationalSignificantNumber(phonenUmber);


                    name = lookupNumber(temp);
                    return name;
                }

            } catch (Exception e) {

                e.printStackTrace();

            }
            return number;
        }
    } else {
        return "Invalid Number";
    }
}

private String lookupNumber(String number) {

    uri = Uri.withAppendedPath(
            ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
            Uri.encode(number));
    name = number;

    contentResolver = getContentResolver();
    contactLookup = contentResolver.query(uri, columns, null, null, null);

    try {
        if (contactLookup != null && contactLookup.getCount() > 0) {
            contactLookup.moveToNext();
            name = contactLookup.getString(contactLookup
                    .getColumnIndex(ContactsContract.Data.DISPLAY_NAME));

        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (contactLookup != null) {
            contactLookup.close();
        }
    }

    return name;
}

Hope it solves your problem.


For this type of problem Google itself has provided libraries for us specially meant for android phones. Don't use any type of wired code take a look at Google's official library tested by experienced developers.

Use libphonenumber google library meant for for parsing, formatting, storing and validating international phone numbers.

A lot of code snippets aregiven on the this landing page so I think no need to write any code here you can understand them from there only.

http://code.google.com/p/libphonenumber/

They have given al the resource How to parse and How to match.

Features of this library relevant to you.

  • Parsing/formatting/validating phone numbers for all countries/regions of the world.

  • isNumberMatch - gets a confidence level on whether two numbers could be the same.

  • findNumbers - finds numbers in text input.


Try this: Google's library for dealing with phone numbers


I'm not quit shure if I answer your question correct but as I understood this you have the problem, that the phonenumer could appear in two different ways. With or without countrycode.

I guess there will be two easy solutions. The easiest would be to change the read input from your inbox. The inbox will always have the country code which could be trimmed. e.g.

String inboxNo; //the number you've read from the inbox
int length = inboxNo.length     
if ((inboxNo.equals(whatYouAreSearching) || (String withOutCountryCode = "0"+ inboxNo.substring(3,length-1))
...

Other solution could be that you check the first character of your database and convert it e.g.

if(!dataBaseNo.substring(0,1).contanins("+"){
dataBaseNo = "+44" + dataBaseNo.substring(1,length-1);
...

Maybe you can use a static variable (array or something) with all country codes and use 2-pass approach to correctly match the code. If a country code gets added or something, this array could be refreshed either by update or if you need to be really good, pull from a standard source online and trigger periodic update from your app.

private static int countrycodes[]; // define the entire data here
...
{
...
for(int i=0;i<countrycodes.length;i++){
    //match using regexp or something and flag this for 2nd pass
    }
}

Although my solution may look dirty, but this may do the trick.

    String number = "your number";
    ContentResolver contentResolver; // content resolver
    Contact c;
    if (number != null) {
        if (number.charAt(0) == '+') {
            c = getContact(number.substring(1), contentResolver);
            if (c.firstField == -1) {
                c = getContact(number.substring(2), contentResolver);
                if (c.firstField == -1) {
                    c = getContact(number.substring(3), contentResolver);
                }
            }
        } else {
            c = getContact(number, contentResolver);
            if (c.firstField == -1) {
                c = getContact(number.substring(1), contentResolver);
                if (c.firstField == -1) {
                    c = getContact(number.substring(2), contentResolver);
                }
            }
        }
    }

Hope it helps...


This technique works for me, to parse partial number, by using:

//encode the phone number and build the filter URI
Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number.substring(len-9)));

String selection = PhoneLookup.NUMBER + " LIKE %" + number.substring(len-9) + "%";

Cursor cursor = context.getContentResolver().query(contactUri, projection, selection, null, null);

Complete Example:

private void getContactDetails(String number) {
    // define the columns you want the query to return
    String[] projection = new String[] {
        PhoneLookup.DISPLAY_NAME,
        PhoneLookup._ID,
        PhoneLookup.LOOKUP_KEY};
    int len = number.length();
    // encode the phone number and build the filter URI
    Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number.substring(len-9)));

    String selection = PhoneLookup.NUMBER + " LIKE %" + number.substring(len-9) + "%";

    Cursor cursor = context.getContentResolver().query(contactUri, projection, selection, null, null);

    if(cursor != null) {
        if (cursor.moveToFirst()) {
            String name = cursor.getString(cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME));
            String lookUpKey = cursor.getString(cursor.getColumnIndex(PhoneLookup.LOOKUP_KEY));
        }
        cursor.close();
    }
}

It parses and matches last 10 digits of number, hope it will help !!!


Need Your Help

'chcp' is not recognized as an internal or external command, operable program or batch file. on a Windows PC

windows git command-line environment-variables

I am receiving the error message below in the command prompt when using the git init command. I'm using a Windows PC running Windows 7.

How to denote 160 bits SHA-1 string as 20 characters in ANSI?

hash encoding character-encoding hex ascii

For an input "hello", SHA-1 returns "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", which are 40 hex outputs. I know 1 byte can denote as 1 character, so the 160 bits output should be able to converted...