Android - Querying the SMS ContentProvider? - android

I currently register a content observer on the following URI "content://sms/" to listen out for incoming and outgoing messages being sent.
This seems to work ok and I have also tried deleting from the sms database but I can only delete an entire thread from the following URI "content://sms/conversations/"
Here is the code I use for that
String url = "content://sms/";
Uri uri = Uri.parse(url);
getContentResolver().registerContentObserver(uri, true, new MyContentObserver(handler));
}
class MyContentObserver extends ContentObserver {
public MyContentObserver(Handler handler) {
super(handler);
}
#Override public boolean deliverSelfNotifications() {
return false;
}
#Override public void onChange(boolean arg0) {
super.onChange(arg0);
Log.v("SMS", "Notification on SMS observer");
Message msg = new Message();
msg.obj = "xxxxxxxxxx";
handler.sendMessage(msg);
Uri uriSMSURI = Uri.parse("content://sms/");
Cursor cur = getContentResolver().query(uriSMSURI, null, null,
null, null);
cur.moveToNext();
String protocol = cur.getString(cur.getColumnIndex("protocol"));
if(protocol == null){
Log.d("SMS", "SMS SEND");
int threadId = cur.getInt(cur.getColumnIndex("thread_id"));
Log.d("SMS", "SMS SEND ID = " + threadId);
Cursor c = getContentResolver().query(Uri.parse("content://sms/outbox/" + threadId), null, null,
null, null);
c.moveToNext();
int p = cur.getInt(cur.getColumnIndex("person"));
Log.d("SMS", "SMS SEND person= " + p);
//getContentResolver().delete(Uri.parse("content://sms/conversations/" + threadId), null, null);
}
else{
Log.d("SMS", "SMS RECIEVE");
int threadIdIn = cur.getInt(cur.getColumnIndex("thread_id"));
getContentResolver().delete(Uri.parse("content://sms/conversations/" + threadIdIn), null, null);
}
}
}
However I want to be able to get the recipricant and the message text from the SMS Content Provider, can anyone tell me how to do this?
And also how to delete one message instead of an entire thread?

This was already discussed.
To read SMS from the Content provider check:
- android-1-5-reading-sms-messages
Check this threads:
delete-sms-in-android-1-5
how-to-delete-sms-from-inbox-in-android-programmatically
can-we-delete-an-sms-in-android-before-it-reaches-the-inbox
About your comment saying that you are deleting a whole thread instead of a single sms:
Have you tried out this code?

The address column contains the telephone number of the sms sender.
Use cursor.getString(cursor.getColumnIndex("address")) to pull the telephone number as a String. Pop a cursor on content://sms and sort it in date descending order to get the most recent message. You will have to wait for the new message to enter the table otherwise you will pull information from the wrong message. In an incomingSMS broadcastReceiver use a while loop, in a thread, polling for the cursor.getCount() to change. Then after the while loop cursor.moveToFirst will be the new message.
For example:
Cursor cur = getContentResolver().query(Uri.parseUri(content://sms), null, null, null, null);
int count = cur.getCount();
while (cur.getCount() == count)
{
Thread.sleep(1000);
cur = getContentResolver().query(Uri.parseUri(content://sms), null, null, null, null);
}
Then get the address of the sms sender:
cur = getContentResolver().query(Uri.parseUri(content://sms), null, null, null, "date DESC");
cur.MoveToFirst();
String telephoneNumber = cur.getString(cur.getColumnIndex("address");
This while loop will pause the thread until the new message arrives. You can also use a contentObserver, but this while loop is simple and does not require registration, unregistration, and a separate class.
Frankly I think its faster to pull the address and the body of the message directly from the pdu of the incoming intent. This way you dont have to wait for the message to enter the table to get the address and the body. The Android class SmsMessage has a variety of useful methods.

Related

Android-how to delete specific message from sent item or don't show sent message when using following code..?

this is my sample code for sending message i want to use not show this message in sent item.
String strPhone = "XXXXXXXXXXX";
String strMessage = "Lorem\nIpsum";
SmsManager sms = SmsManager.getDefault();
sms.sendTextMessage(strPhone, null, strMessage, null, null);
Toast.makeText(this, "Sent.", Toast.LENGTH_SHORT).show();
i want to delete this sended message from sent items or now show in sent item.
in all version.
please help me to solve out.
Query your conversations after sending the message. Then fetch that particular message by comparing the message contents using any unique keyword in your sent message.I have tried this code in my phone running Marshmallow.
Uri uriSMS = Uri.parse("content://sms/conversations");
Cursor cur = getContentResolver().query(uriSMS, null, null, null, null);
if(cur != null && cur.moveToNext()) {
do {
String smsContent = cur.getString(2);
if(smsContent.contains("your sms keyword")) {
String pid = cur.getString(0); // Get id;
String uri = "content://sms/" + pid;
getContentResolver().delete(Uri.parse(uri), null, null);
}
} while (cur.moveToNext());
}

Mark incoming SMS as Read in Default SMS Application

Sorry if i did not come up with a suitable title.
I want to know that is it possible to mark SMS as read in the default SMS Application through my Application?
i.e. i am developing my own application in which i am storing sms that are not from the contact list but the problem is that when ever sms received it received on my app and also on the default sms app so i want that when ever sms received then i can mark the sms as read(of the default SMS App) so that there is no need for go to default sms app and mark SMS as read.
Can i do that from my Application?
try this code
private void markMessageASRead(Context context, String numb, String body) {
Uri uri = Uri.parse("content://sms/inbox");
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
try{
while (cursor.moveToNext()) {
if ((cursor.getString(cursor.getColumnIndex("address")).equals(number)) && (cursor.getInt(cursor.getColumnIndex("read")) == 0)) {
if (cursor.getString(cursor.getColumnIndex("body")).startsWith(body)) {
String SmsMessageId = cursor.getString(cursor.getColumnIndex("_id"));
ContentValues values = new ContentValues();
values.put("read", true);
context.getContentResolver().update(Uri.parse("content://sms/inbox"), values, "_id=" + SmsMessageId, null);
return;
}
}
}
}catch(Exception e)
{
Log.e("Mark Read", "Error in Read: "+e.toString());
}
}

differentiate inbox and sentsms from all sms

I am working on an ANdroid application.In my app I have to list all the conversations and i did that part.Each conversation is containing all sms to that number. So i have to differtiate inbox and sentsms from all sms.I know about the following api's can use to find inbox and sent.
content://sms/inbox
content://sms/sent
But i don't want to use this.I listed all sms by using the api
content://sms/
I tested with the columnindex's type,address but it always gives the same result for inbox and outbox.And my sample code is
Uri SMS_INBOX = Uri.parse("content://sms");
c = getContentResolver().query(SMS_INBOX, null, "thread_id" + " = "
+ "3", null,
"date" + " ASC");
if(c.moveToFirst()){
count.add(c.getCount());
for(int j=0;j<c.getCount();j++){
System.out.println(c.getString(c.getColumnIndexOrThrow("body")).toString());
System.out.println("new person=="+c.getColumnIndex("person")+"type=="+c.getColumnIndexOrThrow("type"));
c.moveToNext();
}
}
c.close();
Please help me.
You can use ContentObserver here to track sent and received message,
Override onChange() method of ContentObserver and get the sms type and work accordingly. Psuedo code can be as below.
Cursor cursor = mContext.getContentResolver().query(Uri
.parse("content://sms"), null, null, null, null);
String type = cursor.getColumnIndex("type");
if(cursor.getString(type).equalsIgnoreCase("1")){
// sms received
}
else if(cursor.getString(type).equalsIgnoreCase("2")){
//sms sent
}
Registering ContentObserver for SMS,
ContentResolver observer = this.getContentResolver();
observer.registerContentObserver(Uri.parse("content://sms"),
true, new MySMSObserver(new Handler(),this));
Where MySMSObserver will be your class extending ContentObserver with Constructor having argument as Handler and Context,
public MySMSObserver(Handler handler, Context context) {
super(handler);
this.context = context;
}

How can I get an outgoing mms's address in android

I've spent 5 days trying out different things and lots of googling with no luck
I have a broadcast receiver to monitor and backup incoming mms & sms.
The sms - outgoing and incoming is easy no problem. MMS however...
I have a broadcast receiver for incoming MMS, no problem there.
For outgoing MMS however, I use a content observer directed towards content://mms
heres the part registering the content observer from the service class
mo = new MMSObserver(new Handler(),getApplicationContext());
try{
getContentResolver().unregisterContentObserver(mo);
}
finally{
getContentResolver().registerContentObserver(Uri.parse("content://mms"), true, mo);
}
This is the onchange part in the above content observer
public void onChange(boolean bSelfChange)
{
super.onChange(bSelfChange);
Log.i(TAG,"MMSObserver onChange");
ContentResolver contentResolver = context.getContentResolver();
Uri uri = Uri.parse("content://mms");
Cursor cur = contentResolver.quert("content://mms",null,null,null,null)
if(cur.moveToNext()){
String id = cur.getString(cur.getColumnIndex("_id"));
String date = cur.getString (cur.getColumnIndex ("date"));
String address = getAddress(id);
}
}
private static String getAddress(String id){
String selectionAdd = new String("msg_id=" + id);
String uriStr = MessageFormat.format("content://mms/{0}/addr", id);
Uri uriAddress = Uri.parse(uriStr);
Cursor cAdd = context.getContentResolver().query(uriAddress, null,
selectionAdd, null, null);
String name = null;
if (cAdd.moveToFirst()) {
do {
String number = cAdd.getString(cAdd.getColumnIndex("address"));
if (number != null) {
try {
Long.parseLong(number.replace("-", ""));
name = number;
} catch (NumberFormatException nfe) {
if (name == null) {
name = number;
}
}
}
} while (cAdd.moveToNext());
}
if (cAdd != null) {
cAdd.close();
}
return name;
}
The problem is the address column always returns "insert-address-token" for outgoing mms.
Is there any possible way to get the number the mms is going to?
Also I noticed that the content observer is triggered when the message is in draft form not when it is sent or pending. since depending on those uris is generally a bad idea since they're not part of the sdk, i switched to a different method. cataloging all sms & mms messages and storing their _id columns, and just syncing them with the backup. However my problem still remains.
MMS address column is always "insert-address-token"
Any suggestions?
You may want to try something like this:
Uri uri = Uri.parse("content://mms-sms/conversations/" + mThreadId);
String[] projection = new String[] {
"body", "person", "sub", "subject", "retr_st", "type", "date", "ct_cls", "sub_cs", "_id", "read", "ct_l", "st", "msg_box", "reply_path_present", "m_cls", "read_status", "ct_t", "status", "retr_txt_cs", "d_rpt", "error_code", "m_id", "date_sent", "m_type", "v", "exp", "pri", "service_center", "address", "rr", "rpt_a", "resp_txt", "locked", "resp_st", "m_size"
};
String sortOrder = "normalized_date";
Cursor mCursor = getActivity().getContentResolver().query(uri, projection, null, null, sortOrder);
String messageAddress;
int type;
while (mCursor.moveToNext()) {
String messageId = mCursor.getString(mCursor.getColumnIndex("_id"));
Uri.Builder builder = Uri.parse("content://mms").buildUpon();
builder.appendPath(messageId).appendPath("addr");
Cursor c = mContext.getContentResolver().query(builder.build(), new String[] {
"*"
}, null, null, null);
while (c.moveToNext()) {
messageAddress = c.getString(c.getColumnIndex("address"));
if (!messageAddress.equals("insert-address-token")) {
type = c.getInt(c.getColumnIndex("type"));
c.moveToLast();
}
}
c.close();
}
I am not actually calling the mCursor's moveToNext() method in my code but instead I am implementing this logic in the getView() method of a SimpleCursorAdapter.

Deleting Android SMS programmatically

I want to delete some certain SMS automatically in my Android application. Therefore I have a method which does exactly what I want it to do. However, it only works if I deploy the application directly to my phone from Eclipse. Then it deletes incoming SMS. However, it does not work if the application is downloaded from the market. But there is also no error. Does anybody know how I can solve this or does this only work on rooted devices?
public void deleteSMS(Context context, String message, String number) {
try {
mLogger.logInfo("Deleting SMS from inbox");
Uri uriSms = Uri.parse("content://sms/inbox");
Cursor c = context.getContentResolver().query(uriSms,
new String[] { "_id", "thread_id", "address",
"person", "date", "body" }, null, null, null);
if (c != null && c.moveToFirst()) {
do {
long id = c.getLong(0);
long threadId = c.getLong(1);
String address = c.getString(2);
String body = c.getString(5);
if (message.equals(body) && address.equals(number)) {
mLogger.logInfo("Deleting SMS with id: " + threadId);
context.getContentResolver().delete(
Uri.parse("content://sms/" + id), null, null);
}
} while (c.moveToNext());
}
} catch (Exception e) {
mLogger.logError("Could not delete SMS from inbox: " + e.getMessage());
}
}
Actually, the code in my post is 100% correct. The problem was that Android needs some time to store the SMS upon receiving it. So the solution is to just add a handler and delay the delete request for 1 or 2 seconds.
This actually solved the whole issue.
EDIT (thanks to Maksim Dmitriev):
Please consider that you can't delete SMS messages on devices with Android 4.4.
Also, the system now allows only the default app to write message data to the provider, although other apps can read at any time.
http://developer.android.com/about/versions/kitkat.html
No exception will be thrown if you try; nothing will be deleted. I have just tested it on two emulators.
How to send SMS messages programmatically
Please consider that you can't delete SMS messages on devices with Android 4.4.
Also, the system now allows only the default app to write message data
to the provider, although other apps can read at any time.
http://developer.android.com/about/versions/kitkat.html
No exception will be thrown if you try; nothing will be deleted. I have just tested it on two emulators.
How to send SMS messages programmatically
hey use this code to delete customize sms
1. By date
2. By number
3. By body
try {
Uri uriSms = Uri.parse("content://sms/inbox");
Cursor c = context.getContentResolver().query(
uriSms,
new String[] { "_id", "thread_id", "address", "person",
"date", "body" }, "read=0", null, null);
if (c != null && c.moveToFirst()) {
do {
long id = c.getLong(0);
long threadId = c.getLong(1);
String address = c.getString(2);
String body = c.getString(5);
String date = c.getString(3);
Log.e("log>>>",
"0--->" + c.getString(0) + "1---->" + c.getString(1)
+ "2---->" + c.getString(2) + "3--->"
+ c.getString(3) + "4----->" + c.getString(4)
+ "5---->" + c.getString(5));
Log.e("log>>>", "date" + c.getString(0));
ContentValues values = new ContentValues();
values.put("read", true);
getContentResolver().update(Uri.parse("content://sms/"),
values, "_id=" + id, null);
if (message.equals(body) && address.equals(number)) {
// mLogger.logInfo("Deleting SMS with id: " + threadId);
context.getContentResolver().delete(
Uri.parse("content://sms/" + id), "date=?",
new String[] { c.getString(4) });
Log.e("log>>>", "Delete success.........");
}
} while (c.moveToNext());
}
} catch (Exception e) {
Log.e("log>>>", e.toString());
}
You can choose which app is the default SMS app in 4.4+ and if your app is set as the default it will be able to delete SMS as well.
to make app as default app see this.
Check if your app is default sms app before deleting.
Use the URI provided by telephony class instead of hardcoding.
public void deleteSMS(Context context,int position)
{
Uri deleteUri = Uri.parse(Telephony.Sms.CONTENT_URI);
int count = 0;
Cursor c = context.getContentResolver().query(deleteUri, new String[]{BaseColumns._ID}, null,
null, null); // only query _ID and not everything
try {
while (c.moveToNext()) {
// Delete the SMS
String pid = c.getString(Telephony.Sms._ID); // Get _id;
String uri = Telephony.Sms.CONTENT_URI.buildUpon().appendPath(pid)
count = context.getContentResolver().delete(uri,
null, null);
}
} catch (Exception e) {
}finally{
if(c!=null) c.close() // don't forget to close the cursor
}
}
it delete all(inbox,outbox,draft) the SMS.
private int deleteMessage(Context context, SmsMessage msg) {
Uri deleteUri = Uri.parse("content://sms");
int count = 0;
#SuppressLint("Recycle") Cursor c = context.getContentResolver().query(deleteUri, null, null, null, null);
while (c.moveToNext()) {
try {
// Delete the SMS
String pid = c.getString(0); // Get id;
String uri = "content://sms/" + pid;
count = context.getContentResolver().delete(Uri.parse(uri),
null, null);
} catch (Exception e) {
}
}
return count;
}
use this code.............
or
getContentResolver().delete(Uri.parse("content://sms/conversations/" + threadIdIn), null, null);
I was looking for a method to delete all SMS with one click. Thanks to this post I succeeded.
Here is my method if it interests someone :
private void deleteSMS(){
Uri myUri= Uri.parse("content://sms/");
Cursor cursor = getContext().getContentResolver().query(myUri, null,null,null,null);
while (cursor.moveToNext()) {
int thread_id = cursor.getInt(1);
getContext().getContentResolver().delete(Uri.parse("content://sms/conversations/" + thread_id),null,null);
}
cursor.close();
}
if you want get a message and your sms app your android device phone didn't send any notification use Binary (Data) SMS.

Categories

Resources