Android SMS: group by its thread id - android

I am implementing a SMS App, till now i achieved to get all the messages(sent, received, drafts) with its contact number, thread id, contact id, date, type.
Here is my code:
Uri mSmsinboxQueryUri = Uri.parse("content://sms");
Cursor cursor = _context.getContentResolver().query(
mSmsinboxQueryUri,
new String[] { "_id", "thread_id", "address", "date", "body",
"type" }, null, null, null);
String[] columns = new String[] { "address", "thread_id", "date",
"body", "type" };
if (cursor.getCount() > 0) {
while (cursor.moveToNext()) {
String address = null, date = null, msg = null, type = null, threadId = null;
address = cursor.getString(cursor.getColumnIndex(columns[0]));
threadId = cursor.getString(cursor.getColumnIndex(columns[1]));
date = cursor.getString(cursor.getColumnIndex(columns[2]));
msg = cursor.getString(cursor.getColumnIndex(columns[3]));
type = cursor.getString(cursor.getColumnIndex(columns[4]));
Log.e("SMS-inbox", "\nTHREAD_ID: "
+ threadId + "\nNUMBER: " + address + "\nTIME: " + date + "\nMESSAGE: " + msg + "\nTYPE: " + type);
}
}
}
Now, I need to separate these messages by thread id (messages with same thread id). How can I best achieve that? Thanks!

I would not save those strings seperatly in the first place.
What I would do is a class like:
public class SmsMsg {
private String address = null;
private String threadId = null;
private String date = null;
private String msg = null;
private String type = null;
//c'tor
public SmsMsg(Cursor cursor) {
this.address = cursor.getString(cursor.getColumnIndex("address"));
this.threadId = cursor.getString(cursor.getColumnIndex("thread_id"));
this.date = cursor.getString(cursor.getColumnIndex("date"));
this.msg = cursor.getString(cursor.getColumnIndex("body"));
this.type = cursor.getString(cursor.getColumnIndex("type"));
}
}
now you can instantiate an object of SmsMsg in your while-loop as long cursor.moveToNext() is true and add it to a List of your choice.
You now could copy all messages of a desired threadId to a different List and sort it by date for example. That depends on what you want do do with it.

Related

How i do get all contacts including raw contacts in under 5 seconds

I want to fetch all contact data including all raw contacts.
I referred this link
and this is the code that i am using :
Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, Long.valueOf(raw_contact_id));
Uri entityUri = Uri.withAppendedPath(rawContactUri, Entity.CONTENT_DIRECTORY);
Cursor c = getContentResolver().query(entityUri,
new String[] { RawContacts.SOURCE_ID, Entity.DATA_ID, Entity.MIMETYPE, Entity.DATA1,
Entity.DATA2, Entity.DATA3, Entity.DATA4, Entity.DATA5, Entity.DATA6, Entity.DATA7,
Entity.DATA8, Entity.DATA9, Entity.DATA10, Entity.DATA11, Entity.DATA12, Entity.DATA13,
Entity.DATA14/* , Entity.DATA15 */ },
null, null, null);
try {
while (c.moveToNext()) {
String sourceId = c.getString(0);
if (!c.isNull(1)) {
String mimeType = c.getString(2);
// if (!mimeType.contains("photo")) {
String data1 = c.getString(3);
String data2 = c.getString(4);
String data3 = c.getString(5);
String data4 = c.getString(6);
}
}
} finally {
c.close();
}
The problem is that the implementation of this code takes a lot of time to fetch all contacts-data.
Is there any other way to get the contacts-data in under 5 seconds.
This is how I am getting the name & email Address, you can retrieve the other data also
ArrayList<String> emailAddressList = new ArrayList<String>();
ArrayList<String> contactNameList = new ArrayList<String>();
HashSet<String> emlRecsHS = new HashSet<String>();
ContentResolver cr = getContentResolver();
String[] PROJECTION = new String[] {ContactsContract.CommonDataKinds.Email.DATA, ContactsContract.Contacts.DISPLAY_NAME};
String order = "CASE WHEN "
+ ContactsContract.Contacts.DISPLAY_NAME
+ " NOT LIKE '%#%' THEN 1 ELSE 2 END, "
+ ContactsContract.Contacts.DISPLAY_NAME
+ ", "
+ ContactsContract.CommonDataKinds.Email.DATA
+ " COLLATE NOCASE";
String filter = ContactsContract.CommonDataKinds.Email.DATA + " NOT LIKE ''";
Cursor cur = cr.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, PROJECTION, filter, null, order);
if (cur.moveToFirst())
{
do
{
// names comes in hand sometimes
String emlAddress = cur.getString(0);
String contactName = cur.getString(1);
// keep unique only
if (emlRecsHS.add(emlAddress.toLowerCase(Locale.US)))
{
emailAddressList.add(emlAddress);
contactNameList.add(contactName);
}
} while (cur.moveToNext());
}
cur.close();

Load Sms from inbox for specific number

I have implemented the code to get sms from inbox to my app.It gets all messages.But I want to load messages from specific number.I followed the tutorial from [Read all SMS from a particular sender it shows empty view.I worked out this code.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.inbox);
ListView list = (ListView) findViewById(R.id.listView1);
List<String> msgList = getSMS();
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, msgList);
list.setAdapter(adapter);
}
public List<String> getSMS() {
List<String> sms = new ArrayList<String>();
// StringBuilder smsBuilder = new StringBuilder();
final String SMS_URI_INBOX = "content://sms/inbox";
final String SMS_URI_ALL = "content://sms/";
try {
Uri uri = Uri.parse(SMS_URI_INBOX);
String[] projection = new String[] { "_id", "address", "person", "body", "date", "type" };
Cursor cur = getContentResolver().query(uri, projection, "address='5558'", null, null);
if (cur.moveToFirst()) {
int index_Address = cur.getColumnIndex("address");
int index_Person = cur.getColumnIndex("person");
int index_Body = cur.getColumnIndex("body");
int index_Date = cur.getColumnIndex("date");
int index_Type = cur.getColumnIndex("type");
do {
String strAddress = cur.getString(index_Address);
int intPerson = cur.getInt(index_Person);
String strbody = cur.getString(index_Body);
long longDate = cur.getLong(index_Date);
int int_Type = cur.getInt(index_Type);
sms.add("Number: " + strAddress + " .Message: " + strbody);
// smsBuilder.append("[ ");
// smsBuilder.append(strAddress + ", ");
// smsBuilder.append(intPerson + ", ");
// smsBuilder.append(strbody + ", ");
// smsBuilder.append(longDate + ", ");
//smsBuilder.append(int_Type);
// smsBuilder.append(" ]\n\n");
} while (cur.moveToNext());
if (!cur.isClosed()) {
cur.close();
cur = null;
}
else {
// smsBuilder.append("no result!");
} // end if
}} catch (SQLiteException ex) {
Log.d("SQLiteException", ex.getMessage());
}
return sms;
}
I passed address as my another emulator.If I gave null replacing address field of getContentResolver()it will load all sms in inbox.Can anyone help me where I have to modify ?
Use following code,
Uri uri = Uri.parse("content://sms/");
ContentResolver contentResolver = getContentResolver();
String phoneNumber = "+911234567890";
String sms = "address='"+ phoneNumber + "'";
Cursor cursor = contentResolver.query(uri, new String[] { "_id", "body" }, sms, null, null);
System.out.println ( cursor.getCount() );
while (cursor.moveToNext())
{
String strbody = cursor.getString( cursor.getColumnIndex("body") );
System.out.println ( strbody );
}
Following permission is required,
<uses-permission android:name="android.permission.READ_SMS"/>
100% working code :
String[] projection = new String[] { "_id", "thread_id","address", "person", "body", "date", "type" };
Uri uri = Uri.parse("content://sms/");
Cursor c = cr.query(uri, projection,"address='9876543210'",null, "date desc");
int totalSMS = 0;
if (c != null) {
totalSMS = c.getCount();
if (c.moveToFirst()) {
for (int j = 0; j < totalSMS; j++) {
String id = c.getString(c.getColumnIndexOrThrow(Telephony.Sms._ID));
String thread_id = c.getString(c.getColumnIndexOrThrow(Telephony.Sms.THREAD_ID));
String smsDate = c.getString(c.getColumnIndexOrThrow(Telephony.Sms.DATE));
String number = c.getString(c.getColumnIndexOrThrow(Telephony.Sms.ADDRESS));
String body = c.getString(c.getColumnIndexOrThrow(Telephony.Sms.BODY));
String type;
switch (Integer.parseInt(c.getString(c.getColumnIndexOrThrow(Telephony.Sms.TYPE)))) {
case Telephony.Sms.MESSAGE_TYPE_INBOX:
type = "inbox";
messageList.add(new Message(id, thread_id, number, body, smsDate, type));
break;
case Telephony.Sms.MESSAGE_TYPE_SENT:
type = "sent";
messageList.add(new Message(id, thread_id, number, body, smsDate, type));
break;
case Telephony.Sms.MESSAGE_TYPE_OUTBOX:
break;
default:
break;
}
c.moveToNext();
}
}
c.close();

How to Delete last received SMS from inbox in Android

I am developing an Android app in which I want to replace message body of last received SMS with some new text.
I am using BroadcastReceiver in which I want to store the message body of last received SMS in a variable and delete the SMS from inbox and Now after deletion I want to put a new encoded message in the inbox.
Now the issue that I am facing is how to delete last received SMS from inbox. I have developed some code in this respect but It delete second last(previous) SMS from inbox. Please check my code below and help that I could continue my app, I would be very thankful to you for this act of kindness.
public void deleteLastSMS()
{
// abortBroadcast();
String body = null;
String num = null;
try
{
Uri uri = Uri.parse("content://sms/inbox");
Cursor c =contex.getContentResolver().query(uri, null, null ,null,null);
if(c.moveToFirst())
{
body = c.getString(c.getColumnIndexOrThrow("body")).toString();
num = c.getString(c.getColumnIndexOrThrow("address")).toString();
}
int id = c.getInt(0);
int thread_id = c.getInt(1);
Uri thread = Uri.parse( "content://sms");
contex.getContentResolver().delete( thread, "thread_id=? and _id=?", new String[]{String.valueOf(thread_id), String.valueOf(id)} );
}
catch(CursorIndexOutOfBoundsException ee)
{
}
}
I've been looking at this since past hour, this is the stuff i found by far, hop i help :)
void deleteMessage(Context context){
Uri uriSms = Uri.parse("content://sms/inbox");
Cursor c = context.getContentResolver().query(uriSms, null,null,null,null);
int id = c.getInt(0);
int thread_id = c.getInt(1); //get the thread_id
context.getContentResolver().delete(Uri.parse("content://sms/conversations/" + thread_id),null,null);
}
void deleteSMS(Context context){
Uri deleteUri = Uri.parse("content://sms");
context.getContentResolver().delete(deleteUri, "address=? and date=?", new String[] {strMessageFrom,strTimeStamp});
}
public void deleteSMS1(Context context, String message, String number) {
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) + "<-1>"
+ c.getString(3) + "4>" + c.getString(4)
+ "5>" + c.getString(5));
Log.e("log>>>", "date" + c.getString(0));
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());
}
}

MMS sender address problem

I am trying to get the address of the sender but I run into a little problem. If the person that sends the message is the first person in any of the conversations to send one, the query of the content://mms/inbox returns with zero rows?? but when someone sends any other mms message it will return back with the _id fine and i dont understand why the first one wont work right?
private String checkMmsMessages(Context context){
String address = "address";
Cursor curPdu = context.getContentResolver ().query(Uri.parse("content://mms/inbox"), null, null, null, null);
if(curPdu.moveToNext()){ //first MMS message curPdu.moveToNext() is false
String id = curPdu.getString (curPdu.getColumnIndex ("_id"));
Log.v("MMS", "ID1: " + id.toString());
Uri uriAddr = Uri.parse ("content://mms/" + id + "/addr");
Cursor curAddr = context.getContentResolver().query(uriAddr,null,"type=137",null,null);
if(curAddr.moveToNext()){
address = curAddr.getString (curAddr.getColumnIndex ("address"));
Log.v("MMS", "Address1: " + address.toString());
if(address.contentEquals("insert-address-token")){
Cursor curAddr2 = context.getContentResolver().query(uriAddr,null,"type=151", null,null);
if(curAddr2.moveToNext()){
address = curAddr2.getString(curAddr2.getColumnIndex("address"));
}
}
}
}
Log.v("MMS", address.toString());
return address;
}
Also something else that does not make sense is when when i have the phone plugged into the computer and step through the that section with the debugger, that problem does not happen and it gets the address every time.... it only happens when the phone is not connected, i just dont understand?
The problem was I was checking the database before the message was put into the database so I had to put a delay on the check
I think the issue is you are passing a value for selectionArgs instead of null to the query() method. 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.
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();
}
try this...
private String getAddressNumber(String id) {
String selectionAdd = new String("msg_id=" + id);
String uriStr = MessageFormat.format("content://mms/{0}/addr", id);
Uri uriAddress = Uri.parse(uriStr);
Cursor cursor = getContentResolver().query(uriAddress, null, selectionAdd, null, null);
String phoneNum = null;
if (cursor.moveToFirst()) {
do {
String number = cursor.getString(cursor.getColumnIndex("address"));
if (number != null) {
boolean isNumberFormat = true;
try {
Long.parseLong(number.replace("-", ""));
phoneNum = number;
} catch (NumberFormatException e) { // ex) "insert-address-token"
// if (phoneNum == null) {
// phoneNum = number;
// }
isNumberFormat = false;
}
if (isNumberFormat)
break;
}
} while (cursor.moveToNext());
}
if (cursor != null) {
cursor.close();
}
return phoneNum;
}

Android Contact Picker Checklist

I'm trying to create a "select-multiple" contact list where I can allow a user to check more than one contact. What I'm looking for is effectively the same thing as the native activity that appears when composing a message to multiple contacts. Thanks!
At first you need to get a list of contacts and then display it on ListView element. For example I'm using following code to display all users contacts on a ListView:
// Run query on all contacts id
Uri uri = ContactsContract.Contacts.CONTENT_URI;
String[] projection = new String[] { ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME};
String selection = null;//ContactsContract.Contacts.HAS_PHONE_NUMBER + " = '" + ("1") + "'";
String[] selectionArgs = null;
String sortOrder = ContactsContract.Contacts.DISPLAY_NAME
+ " COLLATE LOCALIZED ASC";
ContentResolver contectResolver = getContentResolver();
Cursor cursor = contectResolver.query(uri, projection, selection, selectionArgs,
sortOrder);
//Create buffer
final ArrayList<ContactData> bufferContacts = new ArrayList<ContactData>();
//Load contacts one by one
if(cursor.moveToFirst()) {
while(!cursor.isAfterLast()) {
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
String[] emailProj = new String[]{Email.DATA};
Cursor cursorEmail = contectResolver.query(Email.CONTENT_URI, emailProj,Email.CONTACT_ID + " = ? ", new String[] { id }, null);
String[] phoneProj = new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME};
Cursor cursorPhone = contectResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, phoneProj,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[] { id }, null);
String firstName = "";
String lastName = "";
String email = "";
String displayname = "";
String phoneNmb = "";
if(cursorPhone.moveToFirst()) {
///displayname = cursorPhone.getString(cursorPhone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
phoneNmb = cursorPhone.getString(cursorPhone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
}
cursorPhone.close();
if(cursorEmail.moveToFirst()) {
email = cursorEmail.getString(cursorEmail.getColumnIndex(Email.DATA));
}
cursorEmail.close();
displayname = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
//Divide display name to first and last
String[] names = displayname.split("\\s+");
firstName = displayname;
if(names.length >= 1) {
firstName = names[0];
}
if(names.length >= 2) {
firstName = names[1];
}
final ContactData contactData = new ContactData(id, firstName, lastName, phoneNmb, email, allChecked);
bufferContacts.add(contactData);
//Set list view initialy
runOnUiThread(new Runnable() {
public void run() {
if(contactsAdapter == null) {
ArrayList<ContactData> contacts = new ArrayList<ContactData>();
contactsAdapter = new ContactAdapter(ContactPickerActivity.this, contacts);
lvContacts.setAdapter(contactsAdapter);
}
if(bufferContacts.size() >= BUFFER_INTERVAL) {
addBuffer(bufferContacts);
}
}
});
cursor.moveToNext();
}
}
cursor.close();
runOnUiThread(new Runnable() {
public void run() {
addBuffer(bufferContacts);
}
});
If you don't want to bother yourself with making everything out of scratch then feel free to use my ready library for selecting multiple contacts:
https://github.com/kgadzinowski/Android-Multiple-Contacts-Picker-Library

Categories

Resources