how to get the contact infomation by sms message - android

I'm working on an extend SMS application. And now i can read all the SMS message from the mmssms.db. In the SMS database table, the field 'person' indicate the '_id' in contact table. When 'person' is >= 1, that means the message is sent from people in the contact list. So i can 'managedQuery' from contact table. But the question is, in my mobile phone, the test program sometimes can NOT query the contact infomation even 'person' >= 1. So can somebody show me some correct ways to query contact infomation by 'person' filed in SMS table ?
Here is some sample code which can make my question more clear:
class ContactItem {
public String mName;
}
ContactItem getContact(Activity activity, final SMSItem sms) {
if(sms.mPerson == 0) return null;
Cursor cur = activity.managedQuery(ContactsContract.Contacts.CONTENT_URI,
new String[] {PhoneLookup.DISPLAY_NAME},
" _id=?",
new String[] {String.valueOf(sms.mPerson)}, null);
if(cur != null &&
cur.moveToFirst()) {
int idx = cur.getColumnIndex(PhoneLookup.DISPLAY_NAME);
ContactItem item = new ContactItem();
item.mName = cur.getString(idx);
return item;
}
return null;
}

Ok, as there is no one help me out, i tried to read some open source project code, and i got answer now. As i supposed at the very beginning, the best way to query the contact information from a SMS message, is to query by the NUMBER(also know as ADDRESS):
ContactItem getContactByAddr(Context context, final SMSItem sms) {
Uri personUri = Uri.withAppendedPath(
ContactsContract.PhoneLookup.CONTENT_FILTER_URI, sms.mAddress);
Cursor cur = context.getContentResolver().query(personUri,
new String[] { PhoneLookup.DISPLAY_NAME },
null, null, null );
if( cur.moveToFirst() ) {
int nameIdx = cur.getColumnIndex(PhoneLookup.DISPLAY_NAME);
ContactItem item = new ContactItem();
item.mName = cur.getString(nameIdx);
cur.close();
return item;
}
return null;
}

Related

Count sent sms messages for a single thread

I'm looking for the count of sent sms messages in a particular thread (say, with id 15). I found this How do I get the count of SMS messages per contact into a textview? <-- but it doesn't solve my issue, as it counts both sent and received sms messages. Is it possible to count only sent messages? I think I could query "content://sms/sent" and walk through each SMS, but I wonder if there's a more efficient way.
Thanks
You can query Sms.Conversations with your thread ID, and a selection that restricts the TYPE column to MESSAGE_TYPE_SENT. Since you just want the count, we can do a SELECT COUNT() query, so there's no resources wasted building a Cursor with unused values. For example:
private int getThreadSentCount(String threadId) {
final Uri uri = Sms.Conversations.CONTENT_URI
.buildUpon()
.appendEncodedPath(threadId)
.build();
final String[] projection = {"COUNT(1)"};
final String selection = Sms.TYPE + "=" + Sms.MESSAGE_TYPE_SENT;
int count = -1;
Cursor cursor = null;
try {
cursor = getContentResolver().query(uri,
projection,
selection,
null,
null);
if (cursor != null && cursor.moveToFirst()) {
count = cursor.getInt(0);
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (cursor != null) {
cursor.close();
}
}
return count;
}
The Sms class used above is in the android.provider.Telephony class.
import android.provider.Telephony.Sms;
For reference, Sms.Conversations.CONTENT_URI is equivalent to Uri.parse("content://sms/conversations"), Sms.TYPE is "type", and Sms.MESSAGE_TYPE_SENT is 2.

Load SMS conversation along with contact name

I'm developing a SMS application and come to the following issue. Currently I can read SMS conversation by using provider Telephony.Sms.Conversations by using CursorLoader. From cursor returned by this CursorLoader, I can display conversations's address which are phone numbers.
My question is how to retrieve SMS conversation contact name efficiently to display along with SMS conversation, not the phone number. Is there anyway to load list of contacts from list of phone numbers returned by the CursorLoader before?. Of course I've tried to load one by one contact name by using phone number but that terribly reduce the application performance.
Thank you in advance.
I've been searching for a solution myself and eventually came out with a good compromise in my opinion.
As soon as my query is finished, I store in an HashMap<String, String> contact_map my values as
int SENDER_ADDRESS = cursor.getColumnIndex(Telephony.TextBasedSmsColumns.ADDRESS);
while (cursor.moveToNext()) {
contact_map.put(
cursor.getString(SENDER_ADDRESS),
getContactName(getApplicationContext(), cursor.getString(SENDER_ADDRESS))
);
}
Method getContactName:
public static String getContactName(Context context, String phoneNumber) {
ContentResolver cr = context.getContentResolver();
Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
Cursor cursor = cr.query(uri, new String[]{ContactsContract.PhoneLookup.DISPLAY_NAME}, null, null, null);
if (cursor == null) {
return null;
}
String contactName = null;
if(cursor.moveToFirst()) {
contactName = cursor.getString(cursor.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));
}
if(cursor != null && !cursor.isClosed()) {
cursor.close();
}
if (contactName != null) {
return contactName;
} else {
return phoneNumber;
}
}
EDIT:
I then get the contact name with
String name = contact_map.get(cursor.getString(SENDER_ADDRESS));
Hope it helps!

Frequent queries on android contacts returns null

I'm using the following code segment to get phone numbers of a contact by contact ID
private static ArrayList<PhoneName> getPhonesFromID(Context context,
String contactID, String column) {
// Run query
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String[] projection = new String[] {
ContactsContract.CommonDataKinds.Phone._ID,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.STARRED,
ContactsContract.CommonDataKinds.Phone.TYPE };
String selection = column + " = '" + contactID + "'";
String[] selectionArgs = null;
String sortOrder = ContactsContract.CommonDataKinds.Phone.NUMBER
+ " COLLATE LOCALIZED ASC";
Cursor cursor = context.getContentResolver().query(uri, projection,
selection, selectionArgs, sortOrder);
if (cursor == null)
return null;
int numberIndex = cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
int nameIndex = cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int typeIndex = cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE);
int favIndex = cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.STARRED);
ArrayList<PhoneName> phones = new ArrayList<PhoneName>();
while (cursor.moveToNext()) {
PhoneName pn = new PhoneName();
pn.name = cursor.getString(nameIndex);
pn.number = cursor.getString(numberIndex);
pn.starred = cursor.getString(favIndex);
pn.state = DataHelper.getInstance(context)
.getSubscriptionStateByNumber(pn.number);
Log.d("Number", pn.number);
int type = cursor.getInt(typeIndex);
if (type == ContactsContract.CommonDataKinds.Phone.TYPE_HOME) {
pn.type = "Home";
} else if (type == ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE) {
pn.type = "Mobile";
} else if (type == ContactsContract.CommonDataKinds.Phone.TYPE_WORK) {
pn.type = "work";
} else {
pn.type = "other";
}
phones.add(pn);
}
cursor.close();
return phones;
}
Here's PhoneName is my self-defined class to store contact information of that specific contact. This function is called like:
getPhonesFromID(context, _id,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID);
I'm getting the contact information correctly but here's the problem, sometimes this function returns null when I make frequent queries. When this problem occurs, default people application of my android don't show any contact too. All contacts are like vanished. Then if I close my application and restart then it shows all contacts like before. Then again when I go to the contact details of a contact from my application it works fine several times and then all contacts are gone again.
This is a weird problem and I don't know actually what is happening here. I double checked my queries and couldn't figure out what's wrong in here.
Finally, this problem got solved.
Like I said, my application is like Phonebook and I had to show a favourite icon for each contact in the list which is my favourite contact. In my case, I had a function like isFavourite() to determine if a contact is in my favourite list or not and this is called in every single time when a contact row is loading.
Each time I open a cursor to get the query result and it was found that the cursor was not closed anywhere. So basically, closing the cursor properly solved the problem! Cheers!

Check Incoming number is stored in Contacts list or not android

In my android app when an incoming call i want to show my custom ui and i am able to do this.
No i want to check incoming number is from contacts or not.
Below is my code for doing so but it returns null for an incoming number which is stored in my contacts list.
public String findNameByNumber(String num){
Uri uri = Uri.withAppendedPath(Phones.CONTENT_FILTER_URL, Uri.encode(num));
String name = null;
Cursor cursor = mContext.getContentResolver().query(uri,
new String[] { Phones.DISPLAY_NAME }, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
name = cursor.getString(cursor.getColumnIndex(Phones.DISPLAY_NAME));
cursor.close();
callyName.setText(name+" Calling..");
}
return name;
}
and i have incoming call from a number say+917878787878 but in my contacts this contact is stored as name XYZ with number 78 78 787878,which is formated because between number there are space.and also try by excluding +91 but still it returns null.
So how can i find number which is stored in any format.Which may be stored with country code or not.
Thanks In advance.
Try this code instead (using PhoneLookup.CONTENT_FILTER_URI instead of Phones):
String res = null;
try {
ContentResolver resolver = ctx.getContentResolver();
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
Cursor c = resolver.query(uri, new String[]{PhoneLookup.DISPLAY_NAME}, null, null, null);
if (c != null) { // cursor not null means number is found contactsTable
if (c.moveToFirst()) { // so now find the contact Name
res = c.getString(c.getColumnIndex(CommonDataKinds.Phone.DISPLAY_NAME));
}
c.close();
}
} catch (Exception ex) {
/* Ignore */
}
return res;
As docs says ContactsContract.PhoneLookup: A table that represents the result of looking up a phone number, for example for caller ID. To perform a lookup you must append the number you want to find to CONTENT_FILTER_URI. This query is highly optimized.

Android: Accessing and querying properly using Raw Contact Id

So my app is attempting to integrate a sync adapter to the android native contact manager. This is all running smoothly except once a contact is synced, I am unable to update it. Details on this particular problem can be found here: Android: Content resolver query returning 0 rows when it ought not to But I can sum it up simply by just saying my content resolver query is returning 0 values because I am querying the wrong URI, I believe.
When I write the raw contact id to the phone, I do it with the following code:
public ContactSyncOperations(Context context, String username,
String accountName, BatchOperationForSync batchOperation) {
this(context, batchOperation);
mBackReference = mBatchOperation.size();
mIsNewContact = true;
mValues.put(RawContacts.SOURCE_ID, username);
mValues.put(RawContacts.ACCOUNT_TYPE, "com.tagapp.android");
mValues.put(RawContacts.ACCOUNT_NAME, accountName);
mBuilder = newInsertCpo(RawContacts.CONTENT_URI, true).withValues(mValues);
mBatchOperation.add(mBuilder.build());
}
This constructor method is called when you are adding a new contact to the sync list:
private static void addContact(Context context, String account, Contact contact, BatchOperationForSync batchOperation) {
ContactSyncOperations contactOp = ContactSyncOperations.createNewContact(context, contact.getUsername(), account, batchOperation);//constructor called # this line
contactOp.addName(contact.getFirstName(), contact.getLastName());
contactOp.addEmail(contact.getEmail());
contactOp.addPhone(contact.getPhoneNumber(), Phone.TYPE_MOBILE);
contactOp.addPhone(contact.getHomePhone(), Phone.TYPE_HOME);
contactOp.addPhone(contact.getWorkPhone(), Phone.TYPE_WORK);
contactOp.addProfileAction(contact.getUsername());
Log.e("Adding contact", "Via sync");
}
As you can see in the constructor, I am calling a method called newInsertCpo, which can be viewed here:
private void addInsertOp() {
if(!mIsNewContact) {
mValues.put(Phone.RAW_CONTACT_ID, mRawContactId);
}
mBuilder = newInsertCpo(addCallerIsSyncAdapterParameter(Data.CONTENT_URI), mYield);
mBuilder.withValues(mValues);
if(mIsNewContact) {
mBuilder.withValueBackReference(Data.RAW_CONTACT_ID, mBackReference);
}
mYield = false;
mBatchOperation.add(mBuilder.build());
}
Now that you can see the code, let me explain the problem. When I am creating and writing the raw contact id, I am doing so to RawContacts.CONTENT_URI:
mBuilder = newInsertCpo(RawContacts.CONTENT_URI, true).withValues(mValues);
However, when I query the uri, I am querying as so:
Cursor cursor = resolver.query(Data.CONTENT_URI, DataQuery.PROJECTION, DataQuery.SELECTION, new String[] {String.valueOf(rawContactId)}, null);
From Data.CONTENT_URI. I believe this is where my problem is occurring. I used the sample code from Android's official dev site and tailored it for my own uses, but this part is pretty true to the example. Yet it is not working. My lead is what I said, I'm writing to one Uri and querying another. But I've attempted to change the query to RawContacts.CONTENT_URI (which caused an exception), and also changing the Uri I write to Data.CONTENT_URI, which also causes an exception. What's even more confusing is that I get raw contact ids from Data.CONTENT_URI when I do my lookupRawContactId method:
private static long lookupRawContact(ContentResolver resolver, String username) {
Log.e("Looking up Raw Contact", username);
long authorId = 0;
Cursor cursor = resolver.query(Data.CONTENT_URI, UserIdQuery.PROJECTION, UserIdQuery.SELECTION, new String[] {username}, null);
try {
if(cursor != null && cursor.moveToFirst()) {
authorId = cursor.getLong(UserIdQuery.COLUMN_ID);
}
} finally {
if(cursor != null) {
cursor.close();
}
}
return authorId;
}
So yea, if I get a cursor returning rawcontactId, why would I get 0 values querying that same Uri with that same rawcontactId i was returned? It doesn't make any sense! Does anyone have any insight? Thanks all.
The lookupRawContactId method should look like this instead:
private static long lookupRawContact(ContentResolver resolver, String username) {
Log.e("Looking up Raw Contact", username);
long authorId = 0;
Cursor cursor = resolver.query(RawContacts.CONTENT_URI, UserIdQuery.PROJECTION, UserIdQuery.SELECTION, new String[] {username}, null);
try {
if(cursor != null && cursor.moveToFirst()) {
authorId = cursor.getLong(UserIdQuery.COLUMN_ID);
}
} finally {
if(cursor != null) {
cursor.close();
}
}
return authorId;
}
Notice the query is searching RawContacts.CONTENT_URI instead.

Categories

Resources