27

I try the following code to remove contact with a specified number:

private void removeContact(Context context, String phone) {
    //context.getContentResolver().delete(Contacts.Phones.CONTENT_URI, phone, null);
    context.getContentResolver().delete(Contacts.Phones.CONTENT_URI,
          Contacts.PhonesColumns.NUMBER+"=?", new String[] {phone});
}

But I get this exception:

java.lang.UnsupportedOperationException: Cannot delete that URL: content://contacts/phones
    at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:130)
    at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:110)
    at android.content.ContentProviderProxy.delete(ContentProviderNative.java:362)
    at android.content.ContentResolver.delete(ContentResolver.java:386)

Can you please tell me how to fix my problem?

Thank you.

Arun J
  • 687
  • 4
  • 14
  • 27
yinglcs
  • 2,891
  • 6
  • 26
  • 20

7 Answers7

24

To delete all contacts use the following code:

ContentResolver cr = getContentResolver();
    Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,
            null, null, null, null);
    while (cur.moveToNext()) {
        try{
            String lookupKey = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
            Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey);
            System.out.println("The uri is " + uri.toString());
            cr.delete(uri, null, null);
        }
        catch(Exception e)
        {
            System.out.println(e.getStackTrace());
        }
    }

To delete any specific contact modify the query

cr.delete(uri, null, null);

Hope it helps!

Prateek Jain
  • 1,234
  • 14
  • 24
  • 1
    Yes it is working but the problem is that it is not removing contact from `data` table of contact2.db(android database) database. – Vivek Sep 15 '11 at 01:36
  • 2
    modify the query to what? – CHarris May 22 '16 at 21:08
  • `java.lang.IllegalStateException: Couldn't read row 1323, col 16 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.` after every 1323 contacts deletion, I am trying to delete about 100k contacts from device. – Omkar Apr 06 '17 at 15:08
21

This is all we need. To delete Contact with phone number and name given

public static boolean deleteContact(Context ctx, String phone, String name) {
    Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phone));
    Cursor cur = ctx.getContentResolver().query(contactUri, null, null, null, null);
    try {
        if (cur.moveToFirst()) {
            do {
                if (cur.getString(cur.getColumnIndex(PhoneLookup.DISPLAY_NAME)).equalsIgnoreCase(name)) {
                    String lookupKey = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
                    Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey);
                    ctx.getContentResolver().delete(uri, null, null);
                    return true;
                }

            } while (cur.moveToNext());
        }

    } catch (Exception e) {
        System.out.println(e.getStackTrace());
    } finally {
        cur.close();
    }
    return false;
}

And remind to add read/write contact permission

<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
rude
  • 2,340
  • 2
  • 14
  • 19
Khai Nguyen
  • 3,065
  • 1
  • 31
  • 24
9

Do you have the appropriate permissions declared in your manifest?

You'll need the android.permission.READ_CONTACTS and android.permission.WRITE_CONTACTS uses-permission tags before Android will let you mess with the contacts provider:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.android.app.myapp" >

  <uses-permission android:name="android.permission.READ_CONTACTS" />
  <uses-permission android:name="android.permission.WRITE_CONTACTS" />

</manifest>
Reto Meier
  • 96,655
  • 18
  • 100
  • 72
  • 1
    Permission problems are what kill me the most. There was once I went a week trying to figure out why my vibrate code kept crashing until I figured out you needed a permission to vibrate... – num1 Feb 09 '09 at 14:24
7

A late answer, but maybe it helps anyway:

If you look at the source code of ContactsProvider and search for "matcher.addURI" (don't be surprised if it stops loading in the middle... it resumes loading after a minute or two), then you see that it has a finite set of URI schemes that it can handle. It has a handler for "phones/#" but not for "phones", which is what you would need.

This means, there is just no code to delete all phone numbers, you have to get the IDs of all numbers first, and then delete each one at a time. Of course this takes a lot more CPU and memory resources, but at least it works.

The following code deletes a specific number. Please be aware that I did not test this code, but it is 90% identical to the code I use to delete all numbers of a given person, which needs similar treatment beacause Android can't delete "people/#/phones" but "people/#/phones/#"

EDIT: I just realized that I misunderstood the question. I thought you would like to delete the phone number, which my code does. But now I see you want to delete the contanct.

private void deletePhoneNumber(Uri peopleUri, String numberToDelete) {

    Uri.Builder builder = peopleUri.buildUpon();
    builder.appendEncodedPath(People.Phones.CONTENT_DIRECTORY);
    Uri phoneNumbersUri = builder.build();


    String[] mPhoneNumberProjection = { People.Phones._ID, People.Phones.NUMBER };
    Cursor cur = resolver.query(phoneNumbersUri, mPhoneNumberProjection,
            null, null, null);

    ArrayList<String> idsToDelete = new ArrayList<String>();

    if (cur.moveToFirst()) {
        final int colId = cur.getColumnIndex(People.Phones._ID);
        final int colNumber = cur.getColumnIndex(People.Phones.NUMBER);

        do {
            String id = cur.getString(colId);
            String number = cur.getString(colNumber);
            if(number.equals(numberToDelete))
                idsToDelete.add(id);
        } while (cur.moveToNext());
    }
    cur.close();

    for (String id : idsToDelete) {
        builder.encodedPath(People.Phones.CONTENT_DIRECTORY + "/" + id);
        phoneNumbersUri = builder.build();
        resolver.delete(phoneNumbersUri, "1 = 1", null);
    }
}

The code is a bit verbose because it makes two assumptions:

  • there could be multiple lines to delete (e.g. the number is stored twice)
  • it might be unsafe to get a cursor, delete a row, and keep using the cursor

Both assumptions are handled by first storing the idsToDelete in an ArrayList and then deleting.

You might also consider to normalize the number you search for, and use the Column People.Phones.NUMBER_KEY instead, because it contains the numbers in normalized form.

Lena Schimmel
  • 7,203
  • 5
  • 43
  • 58
  • Maybe it was me being stupid, but it took me a while to figure out that a call to this function needed to be like deletePhoneNumber(Contacts.CONTENT_URI,"555"); to work. Otherwise a great answer, thanks! – pgsandstrom Feb 11 '10 at 09:40
1

A better way to delete a contact is by removing all raw contacts using contact id

    final ArrayList ops = new ArrayList();
    final ContentResolver cr = getContentResolver();
    ops.add(ContentProviderOperation
            .newDelete(ContactsContract.RawContacts.CONTENT_URI)
            .withSelection(
                    ContactsContract.RawContacts.CONTACT_ID
                            + " = ?",
                    new String[] { allId.get(i) })
            .build());

        try {
            cr.applyBatch(ContactsContract.AUTHORITY, ops);
            int deletecontact = serialList.get(allId.get(i));

        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        }
        //background_process();
        ops.clear();
    }

and dont forget to add permissions

        <uses-permission android:name="android.permission.READ_CONTACTS"/>
        <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
  • why declaring variable as final? Moreover you don't need cr variable -> could use direct getContentResolver().applyBatch(* – user8462556 Apr 22 '20 at 10:40
1

This code works perfect for me to remove the contact from its identifier (ContactsContract.Contacts._ID)

Telephone registration for all numbers of that contact must be removed independently

  fun deleteContactById(id: String) {
      val cr = context.contentResolver
      val cur = cr.query(ContactsContract.Contacts.CONTENT_URI,
                    null, null, null, null)
      cur?.let {
          try {
                    if (it.moveToFirst()) {
                        do {
                            if (cur.getString(cur.getColumnIndex(ContactsContract.PhoneLookup._ID)) == id) {
                                val lookupKey = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY))
                                val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey)
                                cr.delete(uri, null, null)
                                break
                            }

                        } while (it.moveToNext())
                    }

                } catch (e: Exception) {
                    println(e.stackTrace)
                } finally {
                    it.close()
                }
            }
}
Sergio Sánchez Sánchez
  • 1,694
  • 3
  • 28
  • 48
0
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,
        null, null, null, null);
while (cur.moveToNext()) {
    try{
        String lookupKey = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
        Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey);
        System.out.println("The uri is " + uri.toString());
        cr.delete(uri, null, null);
    }
    catch(Exception e)
    {
        System.out.println(e.getStackTrace());
    }
}

I have used this code to delete contacts.It will delete sim contacts as well phone contacts or only contacts stored in phone storage.

Tirtha
  • 351
  • 2
  • 6
  • 22
  • 2
    Be careful with the above code. In its current form I believe it will delete every contact on your phone. – CHarris May 22 '16 at 10:08
  • This code has just deleted everything from my phone contacts! Be careful guys! – JPerk May 17 '17 at 21:18