I want to display a list of the contact names from the SMS inbox and outbox (like in the native messaging app). I have come up with the following code:
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Uri messagesUri = Uri.parse("content://sms/");
Cursor cursor = getContentResolver().query(messagesUri,new String[] { "_id", "thread_id", "address", "person", "date", "body", "type" }, null, null, null);
startManagingCursor(cursor);
String[] columns = new String[] { "address", "person", "date", "body", "type" };
String sms = "";
if (cursor.getCount() > 0) {
while (cursor.moveToNext()){
String address = cursor.getString(cursor.getColumnIndex(columns[0]));
sms += address + " ";
String contact=address;
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(address));
Cursor cs= getContentResolver().query(uri, new String[]{PhoneLookup.DISPLAY_NAME},PhoneLookup.NUMBER+"='"+address+"'",null,null);
startManagingCursor(cs);
if(cs.getCount()>0)
{
cs.moveToFirst();
contact=cs.getString(cs.getColumnIndex(PhoneLookup.DISPLAY_NAME));
}
listItems.add(contact);
}
}
adapter=new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
listItems);
setListAdapter(adapter);
}
This works when I run the application in an emulator, but when I try to run it on a phone I get a NullPointerException. If I double-click on the error message in the LogCat the following line gets highlighted:
if(cs.getCount()>0)
What is the problem here?
From the documentation for ContentResolver.query(...)
A Cursor object, which is positioned before the first entry, or null
You must always check for null when using a ContentResolver to query for data.
Also from the same documentation.
Use question mark parameter markers such as 'phone=?' instead of explicit values in the selection parameter, so that queries that differ only by those values will be recognized as the same for caching purposes.
So instead of:
Cursor cs= getContentResolver().query(uri, new String[ {PhoneLookup.DISPLAY_NAME},PhoneLookup.NUMBER+"='"+address+"'",null,null);
Do:
Cursor cs= getContentResolver().query(uri, new String[]{PhoneLookup.DISPLAY_NAME},PhoneLookup.NUMBER+"=?",new String[]{address},null);
My first guess would be that cs is null. As to why it is null, I suppose that the carrier/manufacturer could have changed how this is implemented on your device. Without knowing too much about how these systems work, it looks like you are querying against some kind of database and then using a cursor to iterate over the data. If the representation has been changed, the cursor will break. My suggestion would be to see if there is some other solution that is more Google/API driven (as opposed to reading the raw data).
Related
I have a requirement when I need to get the Contact name of the selected numbers from the ANDROID_CONTACTS.
I can get the name of a particular number using ->
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;
}
How can I pass a list of numbers and get their respective names?
Here's the naive approach:
String[] phones = new String[] { "(212) 555-1111", "(212) 555-2222", "(212) 555-3333"};
String selection = Phone.NUMBER + "IN (?,?,?)";
String[] selectionArgs = phones;
String[] projection = new String[] { Phone.NUMBER, Phone.CONTACT_ID, Phone.DISPLAY_NAME };
Cursor cur = getContentResolver().query(Phone.CONTENT_URI, projection, selection, selectionArgs, null);
DatabaseUtils.dumpCursor(cur); // dumps the cursor to logcat
However, this will only work if you enter the phone number in exactly the same format as it is stored in the ContactsContract DB under NUMBER.
The nice thing about the PhoneLookup.CONTENT_FILTER_URI API you've used is that the format of the number doesn't matter, it'll find it in the DB in any format you use.
To replicate something like that, you can try using another field called NORMALIZED_NUMBER which should always hold the number in a specific format called E164.
So you can run a query like this:
String[] e164_phones = new String[] { "+12125551111", "+12125552222", "+12125553333"};
String selection = Phone.NUMBER + "IN (?,?,?)";
String[] selectionArgs = e164_phones; // all phones here must be in e164 format
String[] projection = new String[] { Phone.NUMBER, Phone.CONTACT_ID, Phone.DISPLAY_NAME };
Cursor cur = getContentResolver().query(Phone.CONTENT_URI, projection, selection, selectionArgs, null);
You'll probably need a way to convert a phone number to E164 format for this code, check out this answer then.
I am creating a messaging application in android and i want to get text messages from unique contact numbers only.
I tried following code but it is not working.
String[] projection = new String[] { "_id","DISTINCT "+ContactsContract.PhoneLookup.NUMBER, "person", "body", "date", "type" };
Cursor cursor = getContentResolver().query(uri, projection,null, null, null);
It throwing error here.
Caused by: android.database.sqlite.SQLiteException: near "DISTINCT": syntax error: , while compiling: SELECT _id, DISTINCT number, person, body, date, type FROM sms ORDER BY date DESC
Can Some one please crack this out for me.
You need to change your query. The DISTINCT keyword only works with all rows. What you need is a Group By section in your query.
You could change your query to:
String[] projection = new String[] { "_id", ContactsContract.PhoneLookup.NUMBER, "person", "body", "date", "type" };
String selection = GROUP BY " + ContactsContract.PhoneLookup.NUMBER;
Cursor cursor = getContentResolver().query(uri, projection, selection, null, null);
I've not tested this yet, so there might be syntax errors.
I wanna make an android app that runs in background and check if there is a miscall or new massage and if it is true do something.How can I run my app in background (it does not close when I click back button) and how to access miscall and new message state I am an amateur in android.
Thanks!
For not seen sms messages there is a column in content://sms that you can check in order to determine if a message has been seen.
Column name is "seen".
example of calling it and checking:
ContentResolver mContectResolver = context.getContentResolver();
Uri uri = Uri.parse("content://sms/");
String[] mProjection = {
"_id",
"address",
"person",
"date",
"body",
"protocol",
"seen"
};
Cursor cursor = mContectResolver.query(uri, mProjection, null, null, null);
cursor.moveToFirst();
for(int i = 0 ; i<cursor.getCount() ; i++){
if(cursor.getString(cursor.getColumnIndexOrThrow("seen")).equalsIgnoreCase("1")){
//Message has not been seen
}
cursor.moveToNext();
}
cursor.close();
Is there a way to tell if a phone number has an sms(s) in android ??
I want to know if there is a way to tell using the sms content porvider I know its not documented and not recommanded to use but is there a way to tell ??
what i have tried .
this statement will get all the inbox sms(s)
cursor = getContentResolver().query(
Uri.parse("content://sms/inbox"), null, null, null,
null);
I cant use the where clause like this
cursor = getContentResolver().query(
Uri.parse("content://sms/inbox"), "address =?", new String[]{"001435436654747"}, null,
null);
because the number may be stored without the global code the "001" or such .
is there a work around for this ??
Hi you can use below code to do this , I use this in my application to listen incoming sms to reply automaticaly.
Uri myMessage = Uri.parse("content://sms/");
ContentResolver cr = getContentResolver();
Cursor c = cr.query(myMessage, new String[] {
"_id", "address", "date", "body",
"read" }, null, null, null);
System.out.println(Number);
while (c.moveToNext()) {
Number = c.getString(c.getColumnIndexOrThrow("address")).toString();
if (Number.equals("001435436654747")) {
// DO YOUR STUFF
}
}
I'm torn about how to implement this because Content Provider URI querys do not support the simple SQL "DISTINCT" query method to return a cursor to the Artists of the songs in the mediastore, removing any duplicate entries.
I can query and get a cursor to all the artists, I'm just torn as to how to remove the dupes, or simply not show them.
I've tried using matrixcursor to construct a new cursor with the dupe entries removed, but it's slow (build an array of artists, if in that array don't copy to the new matrixcursor, etc.)
Can anyone recommend a better solution, or point me in the proper direction??
I've also thought about pre-loading the information i need into an array of objects - I'm just concerned with memory overhead in my application.
Thank You for any help you may provide.
The easiest way to get a list of all the artist (and albums is the same method) is to use the MediaStore.Audio.Artist for the quest. For Example something like this would get and show all the artist:
String[] proj = {MediaStore.Audio.Artists._ID, MediaStore.Audio.Artists.ARTIST, MediaStore.Audio.Artists.NUMBER_OF_ALBUMS, MediaStore.Audio.Artists.NUMBER_OF_TRACKS };
musiccursor = managedQuery(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, proj, null, null, MediaStore.Audio.Artists.ARTIST + " ASC");
String[] from= new String[]{ MediaStore.Audio.Artists.ARTIST, MediaStore.Audio.Artists.NUMBER_OF_ALBUMS, MediaStore.Audio.Artists.NUMBER_OF_TRACKS };
int[] to = new int[] { R.id.songname, R.id.rowlength, R.id.rowartist };
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.musicrow, musiccursor, from, to);
SongsView.setAdapter(adapter);
Where SongsView would be your list to display them in. Everything else is using a simple Cursor adapter
Hope this helps
You might want to try creating stateful CursorWrapper, overriding the appropriate methods. Simply ensure every call to next() iterates through the cursor until it finds an artist name you consider appropriately unique, optionally storing seen artists in an ArrayList instance variable.
ArrayList<SongBeen> genresList=new ArrayList<SongBeen>();
String value=search+ "%";
String[] inValue=new String[] {value};
ContentResolver musicResolver = activity.getContentResolver();
/*Uri musicInUri = android.provider.MediaStore.Audio.Genres.INTERNAL_CONTENT_URI;
Cursor mInternalCursor = musicResolver.query(musicInUri, null, null, null, null);
*/
Uri musicExUri = android.provider.MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI;
Cursor mExternalCursor = musicResolver.query(musicExUri, null, MediaStore.Audio.Genres.NAME+ " like ?",
inValue, "LOWER(" + MediaStore.Audio.Genres.NAME + ") ASC");
Cursor[] cursors = {mExternalCursor};
final MergeCursor mMergeCursor = new MergeCursor(cursors);
if (mMergeCursor.moveToFirst()) {
do {
SongBeen been=new SongBeen();
long thisId= mMergeCursor.getLong(mMergeCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres._ID));
String thisTrack = mMergeCursor.getString(mMergeCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres.NAME));
been.setId(thisId);
been.setTrack(thisTrack);
genresList.add(been);
} while (mMergeCursor.moveToNext());
}
mMergeCursor.close();
return genresList;