I would like to create an SMS with a customised thread ID say "10001". How can I do that ? Reason is because I needed to implement a delete SMS function and the only way to delete a specific SMS thread is either via thread ID OR phone number and getting phone number isnt exactly possible at this point of time hence the needed to define a custom thread ID in my sending of SMS.
I was only able to get a normal SMS working code thus far as below:
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage("+1 203 514 6584", null, "HI Greg! ", null, null);
Thanks in advance for helping out !
The SmsObserver
class is a ContentObserver
that registers itself on the content://sms/
Uri
and checks changes in the SMS table against the recipient's address and message body to retrieve the assigned thread ID for an outgoing SMS message. The class offers an interface that your sending class needs to implement in order to receive the thread ID when it's determined, as this will happen asynchronously.
public class SmsObserver extends ContentObserver {
private static final Handler handler = new Handler();
private static final Uri uri = Uri.parse("content://sms/");
private final Context context;
private final ContentResolver resolver;
private final String address;
private final String body;
public interface OnSmsSentListener {
public void onSmsSent(int threadId);
}
public SmsObserver(Context context, String address, String body) {
super(handler);
if (context instanceof OnSmsSentListener) {
this.context = context;
this.resolver = context.getContentResolver();
this.address = address;
this.body = body;
}
else {
throw new IllegalArgumentException(
"Context must implement OnSmsSentListener interface");
}
}
public void start() {
if (resolver != null) {
resolver.registerContentObserver(uri, true, this);
}
else {
throw new IllegalStateException(
"Current SmsObserver instance is invalid");
}
}
@Override
public void onChange(boolean selfChange, Uri uri) {
Cursor cursor = null;
try {
cursor = resolver.query(uri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
final int type = cursor.getInt(
cursor.getColumnIndex(Telephony.Sms.TYPE));
if(type == Telephony.Sms.Sent.MESSAGE_TYPE_SENT) {
final String address = cursor.getString(
cursor.getColumnIndex(Telephony.Sms.ADDRESS));
final String body = cursor.getString(
cursor.getColumnIndex(Telephony.Sms.BODY));
final int threadId = cursor.getInt(
cursor.getColumnIndex(Telephony.Sms.THREAD_ID));
if (PhoneNumberUtils.compare(address, this.address) &&
body.equals(this.body)) {
((OnSmsSentListener) context).onSmsSent(threadId);
resolver.unregisterContentObserver(this);
}
}
}
}
finally {
if (cursor != null) {
cursor.close();
}
}
}
}
An instance of this needs to be started before the message is sent, and the thread ID will be passed into the sending class's interface method implementation. For example, if you're sending from an Activity
upon clicking a Button
:
public class MainActivity extends Activity
implements SmsObserver.OnSmsSentListener {
...
public void onClick(View v) {
String address = "+1 234 567 8900";
String body = "HI Greg! ";
new SmsObserver(this, address, body).start();
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(address, null, body, null, null);
}
@Override
public void onSmsSent(int threadId) {
// Here's the thread ID.
}
}
Please note that you will need the READ_SMS
permission as well.
A possible alternative is available starting in Lollipop. The URI of the sent message will be attached as a String
extra to the Intent
from the PendingIntent
passed as the fourth argument in the sendTextMessage()
method. The extra will have the key "uri"
, and can be parsed as a Uri
, which can then be used in a query on ContentResolver
to retrieve the thread ID as shown above.
For example, if using a BroadcastReceiver
for the result, the sendTextMessage()
call would be like so:
Intent sentIntent = ...
PendingIntent sentPi = PendingIntent.getBroadcast(context, 0, sentIntent, 0);
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(address, null, body, sentPi, null);
And retrieving the extra in the Receiver would be like so:
public class SmsResultReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
...
String uriString = data.getStringExtra("uri");
Uri uri = Uri.parse(uriString);
// Query as shown above in the ContentObserver
...
}
}