1

I am trying to get all contacts which have mobile numbers. I am able to fetch the contacts.But the problem is it gives me duplicate contacts.same phone number comes two times.

I used the following code to get contacts.

public static List<RawContact>  getAllContacts(Context context,Account account){
        Log.d(TAG, "*** Looking for local contacts with mobile number!!");
        String phoneNumber = null;
        String email = null;
        int numberOfContacts = 0;
        List<RawContact> newContacts = new ArrayList<RawContact>();
        Uri CONTENT_URI = ContactsContract.Contacts.CONTENT_URI;
        String _ID = ContactsContract.Contacts._ID;
        String DISPLAY_NAME = ContactsContract.Contacts.DISPLAY_NAME;
        String HAS_PHONE_NUMBER = ContactsContract.Contacts.HAS_PHONE_NUMBER;

        Uri PhoneCONTENT_URI = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
        String Phone_CONTACT_ID = ContactsContract.CommonDataKinds.Phone.CONTACT_ID;
        String NUMBER = ContactsContract.CommonDataKinds.Phone.NUMBER;

        List<RawContact> localNewContacts = new ArrayList<RawContact>();
        final ContentResolver contentResolver = context.getContentResolver();
        final Cursor cursor = contentResolver.query(CONTENT_URI,
                null,
                null,
                null,
                null);

        if(cursor.getCount()>0){
            numberOfContacts = 0;
            Log.d(TAG, "*** Looking for local contacts "+cursor.getCount());
            while(cursor.moveToNext()){
                String contact_id = cursor.getString(cursor.getColumnIndex(_ID));
                String name = cursor.getString(cursor.getColumnIndex(DISPLAY_NAME));
                int hasPhoneNumber = Integer.parseInt(cursor.getString(cursor.getColumnIndex(HAS_PHONE_NUMBER)));
                final long rawContactId = cursor.getLong(DirtyQuery.COLUMN_RAW_CONTACT_ID);
                if (hasPhoneNumber > 0) {
                    //This is to read multiple phone numbers associated with the same contact
                    Cursor phoneCursor = contentResolver.query(PhoneCONTENT_URI, null, ContactsContract.RawContacts.ACCOUNT_TYPE + " <> 'google' "+" AND "+ Phone_CONTACT_ID + " = ?", new String[]{contact_id}, null);
                    while (phoneCursor.moveToNext()) {
                        phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(NUMBER));
                        Log.d(TAG,"Phone number is: "+phoneNumber);
                        RawContact rawContact = getRawContact(context, rawContactId);
                        Log.d(TAG, "Contact Name: " + rawContact.getBestName());
                        localNewContacts.add(rawContact);
                    }phoneCursor.close();
            }
            numberOfContacts++;
            Log.d(TAG, "numberOfContacts updated: "+numberOfContacts);
        }

    }
        return localNewContacts;
    }

How to solve this issue

Jeeva
  • 1,791
  • 2
  • 23
  • 42

2 Answers2

1

You're getting duplicate contacts because you're actually reading RawContacts, not contacts. Multiple RawContacts can and will contain info about a single person represented by a single Contact.

You need a single query over the Phones table, and organize the data using a HashMap from CONTACT_ID to Contact info, so you won't get duplicates.

The Contacts DB is organized in three main tables:

  1. Contacts - each entry represents one contact, and groups together one or more RawContacts
  2. RawContacts - each entry represents data about a contact that was synced in by some SyncAdapter (e.g. Whatsapp, Google, Facebook, Viber), this groups multiple Data entries
  3. Data - The actual data about a contact, emails, phones, etc. each line is a single piece of data that belongs to a single RawContact

You're trying to make a query on the Contacts table, with projection of fields from the Data table, you can't do that.

You can use something like the following code, just convert the HashMap to work with your ContactModel object:

Map<Long, List<String>> contacts = new HashMap<Long, List<String>>();

String[] projection = { Data.CONTACT_ID, Data.DISPLAY_NAME, Data.MIMETYPE, Data.DATA1, Data.DATA2, Data.DATA3 };
String selection = Data.MIMETYPE + " IN ('" + Phone.CONTENT_ITEM_TYPE + "')";
Cursor cur = cr.query(Data.CONTENT_URI, projection, selection, null, null);

while (cur != null && cur.moveToNext()) {
    long id = cur.getLong(0);
    String name = cur.getString(1);
    String mime = cur.getString(2); // type of data (e.g. "phone")
    String data = cur.getString(3); // the actual info, e.g. +1-212-555-1234
    int type = cur.getInt(4); // a numeric value representing type: e.g. home / office / personal
    String label = cur.getString(5); // a custom label in case type is "TYPE_CUSTOM"

    String labelStr = Phone.getTypeLabel(getResources(), type, label);
    Log.d(TAG, "got " + id + ", " + name + ", " + kind + " - " + data + " (" + labelStr + ")");

    // add info to existing list if this contact-id was already found, or create a new list in case it's new
    List<String> infos;
    if (contacts.containsKey(id)) {
        infos = contacts.get(id);
    } else {
        infos = new ArrayList<String>();
        infos.add("name = " + name);
        contacts.put(id, infos);
    }
    infos.add(kind + " = " + data + " (" + labelStr + ")");
}
marmor
  • 27,641
  • 11
  • 107
  • 150
  • got 411, At Saravanan, kind - +44 7438 306573 (Mobile) 04-18 12:11:19.142 9560-9939/com.example.android.samplesync D/ContactManager: Result executed!! 04-18 12:11:19.142 9560-9939/com.example.android.samplesync D/ContactManager: got 411, At Saravanan, kind - +447438306573 (Mobile) 04-18 12:11:19.142 9560-9939/com.example.android.samplesync D/ContactManager: Result executed!! – Jeeva Apr 18 '18 at 06:45
  • im getting results like this – Jeeva Apr 18 '18 at 06:46
  • 1
    yes, you can format those phones into e164 and compare them to avoid adding similar phones with different format. – marmor Apr 18 '18 at 07:56
  • 1
    see this: https://developer.android.com/reference/android/telephony/PhoneNumberUtils.html#formatNumberToE164(java.lang.String,%20java.lang.String) – marmor Apr 18 '18 at 07:57
  • im trying to sync contacts to my server but only need to show contacts that are using our service in contacts should i give source id value to all contacts or only ones using our service – Jeeva Apr 19 '18 at 05:39
  • how to sync contacts that only use my service?? – Jeeva Apr 19 '18 at 11:28
  • that's not a question i can answer, that's up to your service requirements and design – marmor Apr 29 '18 at 06:22
0

Here is quick solution i came up with

ContentResolver contentResolver = getContentResolver();
        Cursor cursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                                              null,
                                              null,
                                              null,
                                              ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC ");

        contactArray = new ArrayList<>();
        String tempId = "";

        if(cursor != null && cursor.getCount() > 0){
            while(cursor.moveToNext())
            {
                String contact_id = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));

                if(!tempId.equals(contact_id)){
                    String contact_name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                    String contact_number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                    String result = contact_id+"\n"+contact_name+"\n"+contact_number;
                    contactArray.add(result);
                }

                tempId = contact_id;

            }
            ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, contactArray);
            listView.setAdapter(adapter);
            cursor.close();
Gohelboy
  • 1
  • 2
  • While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. – Abhishek Dutt Jul 07 '22 at 08:07