I have code to read contact details and to read birthdays. But how do I get a list of contacts in order of their upcoming birthday?
For a single contact identified by id
, I get details and birthday like this:
Cursor c = null;
try {
Uri uri = ContentUris.withAppendedId(
ContactsContract.Contacts.CONTENT_URI, id);
c = ctx.getContentResolver().query(uri, null, null, null, null);
if (c != null) {
if (c.moveToFirst()) {
DatabaseUtils.cursorRowToContentValues(c, data);
}
}
c.close();
// read birthday
c = ctx.getContentResolver()
.query(
Data.CONTENT_URI,
new String[] { Event.DATA },
Data.CONTACT_ID + "=" + id + " AND "
+ Data.MIMETYPE + "= '"
+ Event.CONTENT_ITEM_TYPE + "' AND "
+ Event.TYPE + "=" + Event.TYPE_BIRTHDAY,
null, Data.DISPLAY_NAME);
if (c != null) {
try {
if (c.moveToFirst()) {
this.setBirthday(c.getString(0));
}
} finally {
c.close();
}
}
return super.load(id);
} catch (Exception e) {
Log.v(TAG(), e.getMessage(), e);
e.printStackTrace();
return false;
} finally {
if (c != null)
c.close();
}
and the code to read all contacts is:
public Cursor getList() {
// Get the base URI for the People table in the Contacts content
// provider.
Uri contacts = ContactsContract.Contacts.CONTENT_URI;
// Make the query.
ContentResolver cr = ctx.getContentResolver();
// Form an array specifying which columns to return.
String[] projection = new String[] { ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME };
Cursor managedCursor = cr.query(contacts, projection, null, null,
ContactsContract.Contacts.DISPLAY_NAME
+ " COLLATE LOCALIZED ASC");
return managedCursor;
}
I did this the other way round - a selection directly to Data table which stores birthday.
private static final int UPCOMING_COUNT = 10;
public static List<BContact> upcomingBirthday(Context ctx) {
String today = new SimpleDateFormat("MM-dd").format(new Date());
List<BContact> firstPart = upcomingBirthday(ctx, today, "12-31", UPCOMING_COUNT);
if (firstPart.size() < UPCOMING_COUNT) {
firstPart.addAll(upcomingBirthday(ctx, "01-01", today, UPCOMING_COUNT - firstPart.size()));
}
return firstPart;
}
public static List<BContact> upcomingBirthday(Context ctx, String fromDate, String toDate, int rows) {
Uri dataUri = ContactsContract.Data.CONTENT_URI;
String[] projection = new String[] { ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Event.CONTACT_ID,
ContactsContract.CommonDataKinds.Event.START_DATE
};
Cursor c = ctx.getContentResolver().query(
dataUri,
projection,
ContactsContract.Data.MIMETYPE + "= ? AND " +
ContactsContract.CommonDataKinds.Event.TYPE + "=" + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY +
" AND substr(" + ContactsContract.CommonDataKinds.Event.START_DATE + ",6) >= ?" +
" AND substr(" + ContactsContract.CommonDataKinds.Event.START_DATE + ",6) <= ?" ,
new String[] {ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE, fromDate, toDate},
"substr("+ ContactsContract.CommonDataKinds.Event.START_DATE +",6)");
List<BContact> result = new ArrayList<BContact>();
int i=0;
while (c.moveToNext() && i<rows) {
result.add(new BContact(c.getString(0), c.getString(1), c.getString(2)));
i++;
}
c.close();
return result;
}
The SELECT is called twice - one call from today to 12/31 and second call from 01/01 to today. I limit returned rows to 10 but this is not necesarry.
EDIT: I found that this won't work on all Android phones as birthday dates are stored in many different format. So you have to load all birthdays (unordered), parse it and sort it in memory. #Fail
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With