How to delete an SMS from the inbox in Android programmatically?

On Android phones SMS messages registered to applications also get sent to the device's inbox. However to prevent clutter, it'd be nice to be able to remove application specific SMS messages from the inbox to reduce the potential overflow of those messages.

Questions on other Google groups on getting a definitive answer on a programmatic way to delete SMS messages from the Android inbox don't seem to be pressing.

So the scenario:

  • Android App startup.
  • register SMS message types X,Y and Z
  • messages P,Q,X,Y,Z stream in over the course of time, all deposited in inbox
  • Android application detects receipt of X,Y,Z (presumably as part of the program interrupt event)
  • process X,Y,Z
  • Desirement!!! X,Y,Z are deleted from the Android inbox

Has it been done? Can it be done?


Solution 1:

"As of Android 1.6, incoming SMS message broadcasts (android.provider.Telephony.SMS_RECEIVED) are delivered as an "ordered broadcast" — meaning that you can tell the system which components should receive the broadcast first."

This means that you can intercept incoming message and abort broadcasting of it further on.

In your AndroidManifest.xml file, make sure to have priority set to highest:

<receiver android:name=".receiver.SMSReceiver" android:enabled="true">
    <intent-filter android:priority="1000">
        <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    </intent-filter>
</receiver>

In your BroadcastReceiver, in onReceive() method, before performing anything with your message, simply call abortBroadcast();

EDIT: As of KitKat, this doesn't work anymore apparently.

EDIT2: More info on how to do it on KitKat here:

Delete SMS from android on 4.4.4 (Affected rows = 0(Zero), after deleted)

Solution 2:

Using suggestions from others, I think I got it to work:

(using SDK v1 R2)

It's not perfect, since i need to delete the entire conversation, but for our purposes, it's a sufficient compromise as we will at least know all messages will be looked at and verified. Our flow will probably need to then listen for the message, capture for the message we want, do a query to get the thread_id of the recently inbounded message and do the delete() call.

In our Activity:

Uri uriSms = Uri.parse("content://sms/inbox");
Cursor c = getContentResolver().query(uriSms, null,null,null,null); 
int id = c.getInt(0);
int thread_id = c.getInt(1); //get the thread_id
getContentResolver().delete(Uri.parse("content://sms/conversations/" + thread_id),null,null);

Note: I wasn't able to do a delete on content://sms/inbox/ or content://sms/all/

Looks like the thread takes precedence, which makes sense, but the error message only emboldened me to be angrier. When trying the delete on sms/inbox/ or sms/all/, you will probably get:

java.lang.IllegalArgumentException: Unknown URL
    at com.android.providers.telephony.SmsProvider.delete(SmsProvider.java:510)
    at android.content.ContentProvider$Transport.delete(ContentProvider.java:149)
    at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:149)

For additional reference too, make sure to put this into your manifest for your intent receiver:

<receiver android:name=".intent.MySmsReceiver">
    <intent-filter>
        <action android:name="android.provider.Telephony.SMS_RECEIVED"></action>
    </intent-filter>
</receiver>

Note the receiver tag does not look like this:

<receiver android:name=".intent.MySmsReceiver" 
    android:permission="android.permission.RECEIVE_SMS">

When I had those settings, android gave me some crazy permissions exceptions that didn't allow android.phone to hand off the received SMS to my intent. So, DO NOT put that RECEIVE_SMS permission attribute in your intent! Hopefully someone wiser than me can tell me why that was the case.