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.
Related
First of all, I am very much new to Android programming.
I have written a program to delete SMS. I have already tested this code in Jelly Bean and it was working fine. Even in simulator with Android Marshmallow is was working fine. Recently I updated my mobile to Marshmallow and now SMS are not getting deleted from the app. Even No error is throw. Below is the code. I search for solution and tried different ways, but still no solution.
public void delete(final String id, final String number, final long date) {
Uri uri = Uri.parse("content://sms/inbox");
ContentResolver cr = context.getContentResolver();
Cursor c = cr.query(uri, null, "person is null and _id = ?", new String[] { "" + id }, null);
if (c != null && c.moveToFirst()) {
do {
String pid = c.getString(c.getColumnIndex("_id"));
String pnumber = c.getString(c.getColumnIndex("address"));
Log.d("MyAPP", "id: " + pid);
if (id.equals(pid) && number.equals(pnumber)) {
Log.d("MyAPP", "Deleting SMS with id: " + id);
try{
cr.delete(Uri.parse("content://sms/" + id), null, null);
Log.d("MyAPP", "Delete success.........");
} catch (Exception ex) {
Log.d("MyAPP", "Error deleting msg");
}
}
} while (c.moveToNext());
}
}
Here is the log.
04-01 22:49:04.783: (1620): id: 39
04-01 22:49:04.783: (1620): Deleting SMS with id: 39
04-01 22:49:04.785: (1620): Delete success.........
I would like to get all messages from one contact. I have the contact ID _id, so I've already do something like this :
private void displayMessages() {
ContentResolver cr = this.getContentResolver();
try {
Cursor cursor = cr.query(Uri.parse("content://mms-sms/conversations"), new String[]{"*"}, this.contID + "= _id" , null, null); //contID is the unique ID for one contact in our android.
while (cursor.moveToNext()) {
System.out.println("Number: " + cursor.getString(cursor.getColumnIndexOrThrow("address")));
System.out.println("Body : " + cursor.getString(cursor.getColumnIndexOrThrow("body")));
}
cursor.close();
}
catch (Exception e) {
System.out.print("ERROR");
}
I've asked something like
SELECT * FROM content://mms-sms/conversations WHERE _id = contID
As you can see, in my query, I ask system for messages from one contact (user id that I know) But I can just display the last message body. So I think it exists others query to get all messages from one user ?
Any ideas ???
I doubt that _id in this case is the id of the contact you are sending sms/mms to but rather the thread's id. The column you probably want to use for your query clause is RECIPIENT_IDS. For debugging purpose try without the where clause and dump the cursor to analyze the results
Cursor cursor = cr.query(Uri.parse("content://mms-sms/conversations"), new String[]{"*"}, null , null, null);
DatabaseUtils.dumpCursor(cursor);
Sorry for answer too late, but I've found a solution.
Here is my code :
private void displayMessages() {
ContentResolver cr = this.getContentResolver();
boolean isMe;
try {
Cursor cursor = cr.query(Uri.parse("content://sms"), null, this.cont.getThread_ID() + " = thread_id" , null, "date ASC");
while (cursor.moveToNext()) {
//if it's a received message :
if ((cursor.getString(cursor.getColumnIndexOrThrow("person")) != null)) {
isMe = false;
}
else {
//it's a message sent by me.
isMe = true;
}
date = cursor.getString(cursor.getColumnIndexOrThrow("date"));
System.out.println("Number: " + cursor.getString(cursor.getColumnIndexOrThrow("address")));
System.out.println("Body : " + cursor.getString(cursor.getColumnIndexOrThrow("body") + "\n");
}
cursor.close();
}
Thanks to "conent://sms" table, I can get all sms !
So I've used thread_id to display all messages, and thanks to the person column, I can know if the message was sent by me or my contact.
Can anybody guide me to find the solution for the following problem.
I have to identify whether the phone contact saved in locally or from Email ?(programatically)
i have read fromgoogle doc that ContactsContract.Groups, which contains information about raw contact groups such as Gmail contact groups. The current API does not support the notion of groups spanning multiple accounts.
Based on that i have tried the following code.
StringBuffer output = new StringBuffer();
final String[] GROUP_PROJECTION = new String[] {
ContactsContract.Groups._ID,
ContactsContract.Groups.TITLE,
ContactsContract.Groups.SUMMARY_WITH_PHONES
};
Cursor c = getContentResolver().query(
ContactsContract.Groups.CONTENT_URI, GROUP_PROJECTION, null,
null, ContactsContract.Groups.TITLE);
int IDX_ID = c.getColumnIndex(ContactsContract.Groups._ID);
int IDX_TITLE = c.getColumnIndex(ContactsContract.Groups.TITLE);
output.append("title"+IDX_TITLE+"\n");
Map<String,GroupInfo> m = new HashMap<String, GroupInfo>();
while (c.moveToNext()) {
output.append("test...\n");
GroupInfo g = new GroupInfo();
g.id = c.getString(IDX_ID);
g.title = c.getString(IDX_TITLE);
output.append("title"+c.getString(IDX_TITLE)+"\n");
int users = c.getInt(c.getColumnIndex(ContactsContract.Groups.SUMMARY_WITH_PHONES));
if (users>0) {
// group with duplicate name?
GroupInfo g2 = m.get(g.title);
if (g2==null) {
m.put(g.title, g);
output.append("title"+g.title+"\n");
groups.add(g);
} else {
g2.id+=","+g.id;
}
}
}
outputText.setText(output);
c.close();
but no hope.
I am posting this answer for future use. We can differentiate the local phone contacts and the sync contacts by using the field called RawContacts.SOURCE_ID
It is described here
SOURCE_ID
read/write
String that uniquely identifies this row to its source account. Typically it is set at the time the raw contact is inserted and never changed afterwards. The one notable exception is a new raw contact: it will have an account name and type (and possibly a data set), but no source id. This indicates to the sync adapter that a new contact needs to be created server-side and its ID stored in the corresponding SOURCE_ID field on the phone.
The sample code is follows, it gives the id for sync contacts and null for others.
private void testContact() {
StringBuffer output = new StringBuffer();
ContentResolver resolver = getContentResolver();
Cursor contacts = resolver.query(Contacts.CONTENT_URI, null,
Contacts.HAS_PHONE_NUMBER + " != 0", null, Contacts._ID
+ " ASC");
Cursor data = resolver.query(Data.CONTENT_URI, null, Data.MIMETYPE
+ "=? OR " + Data.MIMETYPE + "=?", new String[]{
Email.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE},
Data.CONTACT_ID + " ASC");
int idIndex = contacts.getColumnIndexOrThrow(Contacts._ID);
int nameIndex = contacts.getColumnIndexOrThrow(Contacts.DISPLAY_NAME);
int cidIndex = data.getColumnIndexOrThrow(Data.CONTACT_ID);
int data1Index = data.getColumnIndexOrThrow(Data.DATA1);
boolean hasData = data.moveToNext();
while (contacts.moveToNext()) {
long id = contacts.getLong(idIndex);
Uri rawContactUri =
ContentUris.withAppendedId(RawContacts.CONTENT_URI, id);
Uri entityUri =
Uri.withAppendedPath(rawContactUri, Entity.CONTENT_DIRECTORY);
Cursor c =
getContentResolver().query(
entityUri,
new String[] {
RawContacts.ACCOUNT_NAME,
RawContacts.SOURCE_ID, Entity.DATA_ID, Entity.MIMETYPE, Entity.DATA1},
null, null, null);
try {
while (c.moveToNext()) {
String sourceId = c.getString(0);
if (!c.isNull(1)) {
String source_id = c.getString(1);
try {
output.append(c.getString(4)+sourceId+" "+source_id+"\n");
//output.append(datas+ "Sync1 "+ c.getString(4)+" Sync2 "+ c.getString(5)+" Sync3"+ c.getString(6)+" Sync4 "+ c.getString(7)+"\n");
} catch (Exception e) {
e.printStackTrace();
}
//decide here based on mimeType, see comment later
}
}
} finally {
c.close();
}
}
outputText.setText(output);
}
Have a read through this and see if ACCOUNT_TYPE might be able to help you
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.
I'm still very new to android app development, and I have hit a problem I hope u can help me with...
I am trying to retrieve any "Notes" stored against a contact within my phone. I want to check if a contact (current caller) has any notes associated to them, and then either display the contents or do some action depending on the content of them etc...
I have tried the code below as a test to see if the data is retrieved anywhere within my cursor, but although it retrieves some data, I can't see the content of a note - so I guess I'm in the wrong place!
Where I have declared contentID, this is a result of doing a lookup with the code below, and using the id that is recieved.
Uri lookupUri = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, Uri.encode(inCommingNumber));
String[] mPhoneNumberProjection = { Phone._ID, Phone.NUMBER, Phone.DISPLAY_NAME};
Cursor cur = getContentResolver().query(lookupUri , mPhoneNumberProjection, null, null, null);
private boolean hasNote(String contactID){
Boolean noteFound = false;
Cursor noteCur = getContentResolver().query(ContactsContract.Data.CONTENT_URI, null, null, null, null);
if(noteCur.moveToFirst()) {
int numCols = noteCur.getColumnCount();
if(numCols > 0){
for(int x = 0; x < numCols; x++){
Log.d(APP_TAG, " column " + x + " contains: " + noteCur.getString(x));
}
}
noteFound = true;
} else{
Log.d(APP_TAG, "No Note retrieved");
}
noteCur.close();
return noteFound;
}
Apologies, I cant seem to get the code to display properly in this post!!
Any help would be great
I have tried various things, but can't seem to be able to get this data. I have created the note by simply adding it through the normal contact manager. I'm using Android 2.2.
The following code would display the first note for all contacts on your phone:
Cursor contactsCursor = null;
try {
contactsCursor = getContentResolver().query(RawContacts.CONTENT_URI,
new String [] { RawContacts._ID },
null, null, null);
if (contactsCursor != null && contactsCursor.moveToFirst()) {
do {
String rawContactId = contactsCursor.getString(0);
Cursor noteCursor = null;
try {
noteCursor = getContentResolver().query(Data.CONTENT_URI,
new String[] {Data._ID, Note.NOTE},
Data.RAW_CONTACT_ID + "=?" + " AND "
+ Data.MIMETYPE + "='" + Note.CONTENT_ITEM_TYPE + "'",
new String[] {rawContactId}, null);
if (noteCursor != null && noteCursor.moveToFirst()) {
String note = noteCursor.getString(noteCursor.getColumnIndex(Note.NOTE));
Log.d(APP_TAG, "Note: " + note);
}
} finally {
if (noteCursor != null) {
noteCursor.close();
}
}
} while (contactsCursor.moveToNext());
}
} finally {
if (contactsCursor != null) {
contactsCursor.close();
}
}
If you are storing some sort of structured data on the note to take actions on using the free form note field may not be the best approach. With the new contacts contract model you are able to attach your own data fields (in ContactsContract.Data) to a contact just give them your own unique mimetype.