2010-08-14 09:59:33 -04:00
|
|
|
package com.fsck.k9.helper;
|
|
|
|
|
2012-04-08 12:29:08 -04:00
|
|
|
import java.util.ArrayList;
|
|
|
|
|
2013-02-07 14:01:49 -05:00
|
|
|
import android.content.ContentUris;
|
2010-08-14 09:59:33 -04:00
|
|
|
import android.content.Context;
|
|
|
|
import android.content.Intent;
|
|
|
|
import android.database.Cursor;
|
|
|
|
import android.net.Uri;
|
2011-03-22 03:06:11 -04:00
|
|
|
import android.util.Log;
|
2010-10-30 16:35:49 -04:00
|
|
|
import android.provider.ContactsContract;
|
2010-08-14 09:59:33 -04:00
|
|
|
import android.provider.ContactsContract.Contacts;
|
|
|
|
import android.provider.ContactsContract.Intents;
|
|
|
|
import android.provider.ContactsContract.CommonDataKinds.Email;
|
2012-04-01 16:46:36 -04:00
|
|
|
import android.provider.ContactsContract.Intents.Insert;
|
|
|
|
|
2010-08-14 09:59:33 -04:00
|
|
|
import com.fsck.k9.mail.Address;
|
2011-03-22 03:06:11 -04:00
|
|
|
import com.fsck.k9.K9;
|
2010-08-14 09:59:33 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Access the contacts on the device using the API introduced with SDK 5.
|
|
|
|
*
|
|
|
|
* @see android.provider.ContactsContract
|
|
|
|
*/
|
2011-02-06 17:09:48 -05:00
|
|
|
public class ContactsSdk5 extends com.fsck.k9.helper.Contacts {
|
2010-08-14 09:59:33 -04:00
|
|
|
/**
|
|
|
|
* The order in which the search results are returned by
|
|
|
|
* {@link #searchContacts(CharSequence)}.
|
|
|
|
*/
|
2011-01-24 21:34:02 -05:00
|
|
|
protected static final String SORT_ORDER =
|
2010-10-30 16:35:49 -04:00
|
|
|
Email.TIMES_CONTACTED + " DESC, " +
|
|
|
|
Contacts.DISPLAY_NAME + ", " +
|
|
|
|
Email._ID;
|
2010-08-14 09:59:33 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Array of columns to load from the database.
|
|
|
|
*
|
|
|
|
* Important: The _ID field is needed by
|
|
|
|
* {@link com.fsck.k9.EmailAddressAdapter} or more specificly by
|
|
|
|
* {@link android.widget.ResourceCursorAdapter}.
|
|
|
|
*/
|
2011-02-06 17:09:48 -05:00
|
|
|
protected static final String PROJECTION[] = {
|
2010-10-30 16:35:49 -04:00
|
|
|
Email._ID,
|
2010-08-17 22:48:55 -04:00
|
|
|
Contacts.DISPLAY_NAME,
|
2010-10-30 16:35:49 -04:00
|
|
|
Email.DATA,
|
|
|
|
Email.CONTACT_ID
|
2010-08-17 22:48:55 -04:00
|
|
|
};
|
2010-08-14 09:59:33 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Index of the name field in the projection. This must match the order in
|
|
|
|
* {@link #PROJECTION}.
|
|
|
|
*/
|
2011-01-24 21:34:02 -05:00
|
|
|
protected static final int NAME_INDEX = 1;
|
2010-08-14 09:59:33 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Index of the email address field in the projection. This must match the
|
|
|
|
* order in {@link #PROJECTION}.
|
|
|
|
*/
|
2011-01-24 21:34:02 -05:00
|
|
|
protected static final int EMAIL_INDEX = 2;
|
2010-08-14 09:59:33 -04:00
|
|
|
|
2010-10-30 16:35:49 -04:00
|
|
|
/**
|
|
|
|
* Index of the contact id field in the projection. This must match the order in
|
|
|
|
* {@link #PROJECTION}.
|
|
|
|
*/
|
2011-01-24 21:34:02 -05:00
|
|
|
protected static final int CONTACT_ID_INDEX = 3;
|
2010-10-30 16:35:49 -04:00
|
|
|
|
2010-08-14 09:59:33 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public ContactsSdk5(final Context context) {
|
2010-08-14 09:59:33 -04:00
|
|
|
super(context);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void createContact(final Address email) {
|
2010-08-14 09:59:33 -04:00
|
|
|
final Uri contactUri = Uri.fromParts("mailto", email.getAddress(), null);
|
|
|
|
|
|
|
|
final Intent contactIntent = new Intent(Intents.SHOW_OR_CREATE_CONTACT);
|
2011-02-25 13:15:13 -05:00
|
|
|
contactIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
2010-08-14 09:59:33 -04:00
|
|
|
contactIntent.setData(contactUri);
|
|
|
|
|
|
|
|
// Pass along full E-mail string for possible create dialog
|
|
|
|
contactIntent.putExtra(Intents.EXTRA_CREATE_DESCRIPTION,
|
2010-08-17 22:48:55 -04:00
|
|
|
email.toString());
|
2010-08-14 09:59:33 -04:00
|
|
|
|
|
|
|
// Only provide personal name hint if we have one
|
|
|
|
final String senderPersonal = email.getPersonal();
|
2011-02-06 17:09:48 -05:00
|
|
|
if (senderPersonal != null) {
|
2010-08-14 09:59:33 -04:00
|
|
|
contactIntent.putExtra(Intents.Insert.NAME, senderPersonal);
|
|
|
|
}
|
|
|
|
|
2011-01-10 12:47:23 -05:00
|
|
|
mContext.startActivity(contactIntent);
|
2010-08-14 09:59:33 -04:00
|
|
|
}
|
|
|
|
|
2012-04-01 16:46:36 -04:00
|
|
|
@Override
|
|
|
|
public void addPhoneContact(final String phoneNumber) {
|
|
|
|
Intent addIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
|
|
|
|
addIntent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
|
|
|
|
addIntent.putExtra(Insert.PHONE, Uri.decode(phoneNumber));
|
|
|
|
addIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
|
|
mContext.startActivity(addIntent);
|
|
|
|
}
|
|
|
|
|
2010-08-14 09:59:33 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public boolean isInContacts(final String emailAddress) {
|
2010-08-14 09:59:33 -04:00
|
|
|
boolean result = false;
|
|
|
|
|
2010-10-30 16:35:49 -04:00
|
|
|
final Cursor c = getContactByAddress(emailAddress);
|
2010-08-14 09:59:33 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (c != null) {
|
|
|
|
if (c.getCount() > 0) {
|
2010-08-14 09:59:33 -04:00
|
|
|
result = true;
|
|
|
|
}
|
|
|
|
c.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public Cursor searchContacts(final CharSequence constraint) {
|
2010-08-14 09:59:33 -04:00
|
|
|
final String filter = (constraint == null) ? "" : constraint.toString();
|
|
|
|
final Uri uri = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, Uri.encode(filter));
|
|
|
|
final Cursor c = mContentResolver.query(
|
2010-08-17 22:48:55 -04:00
|
|
|
uri,
|
|
|
|
PROJECTION,
|
|
|
|
null,
|
|
|
|
null,
|
|
|
|
SORT_ORDER);
|
2010-08-14 09:59:33 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (c != null) {
|
2010-08-14 09:59:33 -04:00
|
|
|
/*
|
|
|
|
* To prevent expensive execution in the UI thread:
|
|
|
|
* Cursors get lazily executed, so if you don't call anything on
|
|
|
|
* the cursor before returning it from the background thread you'll
|
|
|
|
* have a complied program for the cursor, but it won't have been
|
|
|
|
* executed to generate the data yet. Often the execution is more
|
|
|
|
* expensive than the compilation...
|
|
|
|
*/
|
|
|
|
c.getCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2010-08-30 10:37:34 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public String getNameForAddress(String address) {
|
|
|
|
if (address == null) {
|
2010-10-08 20:24:43 -04:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2010-10-30 16:35:49 -04:00
|
|
|
final Cursor c = getContactByAddress(address);
|
2010-08-30 10:37:34 -04:00
|
|
|
|
2010-10-08 20:24:43 -04:00
|
|
|
String name = null;
|
2011-02-06 17:09:48 -05:00
|
|
|
if (c != null) {
|
|
|
|
if (c.getCount() > 0) {
|
2010-10-08 20:24:43 -04:00
|
|
|
c.moveToFirst();
|
|
|
|
name = getName(c);
|
|
|
|
}
|
|
|
|
c.close();
|
2010-08-30 10:37:34 -04:00
|
|
|
}
|
|
|
|
|
2010-10-08 20:24:43 -04:00
|
|
|
return name;
|
2010-08-30 10:37:34 -04:00
|
|
|
}
|
|
|
|
|
2010-08-14 09:59:33 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public String getName(Cursor c) {
|
2010-08-14 09:59:33 -04:00
|
|
|
return c.getString(NAME_INDEX);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public String getEmail(Cursor c) {
|
2010-08-14 09:59:33 -04:00
|
|
|
return c.getString(EMAIL_INDEX);
|
|
|
|
}
|
2010-10-30 16:35:49 -04:00
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void markAsContacted(final Address[] addresses) {
|
2010-10-30 16:35:49 -04:00
|
|
|
//TODO: Optimize! Potentially a lot of database queries
|
2011-02-06 17:09:48 -05:00
|
|
|
for (final Address address : addresses) {
|
2010-10-30 16:35:49 -04:00
|
|
|
final Cursor c = getContactByAddress(address.getAddress());
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (c != null) {
|
|
|
|
if (c.getCount() > 0) {
|
2010-10-30 16:35:49 -04:00
|
|
|
c.moveToFirst();
|
|
|
|
final long personId = c.getLong(CONTACT_ID_INDEX);
|
|
|
|
ContactsContract.Contacts.markAsContacted(mContentResolver, personId);
|
|
|
|
}
|
|
|
|
c.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-22 03:06:11 -04:00
|
|
|
@Override
|
|
|
|
public Intent contactPickerIntent() {
|
2011-03-23 23:04:13 -04:00
|
|
|
return new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
|
2011-03-22 03:06:11 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2012-04-08 19:04:59 -04:00
|
|
|
public ContactItem extractInfoFromContactPickerIntent(final Intent data) {
|
2011-03-22 03:06:11 -04:00
|
|
|
Cursor cursor = null;
|
2012-04-08 12:29:08 -04:00
|
|
|
ArrayList<String> email = new ArrayList<String>();
|
2011-03-23 23:04:13 -04:00
|
|
|
|
2011-03-22 03:06:11 -04:00
|
|
|
try {
|
|
|
|
Uri result = data.getData();
|
2012-04-08 12:32:04 -04:00
|
|
|
String displayName = null;
|
2011-03-22 03:06:11 -04:00
|
|
|
|
2011-03-23 23:04:13 -04:00
|
|
|
// Get the contact id from the Uri
|
2011-03-22 03:06:11 -04:00
|
|
|
String id = result.getLastPathSegment();
|
|
|
|
|
2012-04-08 19:02:55 -04:00
|
|
|
cursor = mContentResolver.query(Email.CONTENT_URI, PROJECTION,
|
|
|
|
Email.CONTACT_ID + "=?", new String[] { id }, null);
|
|
|
|
|
|
|
|
if (cursor != null) {
|
|
|
|
while (cursor.moveToNext()) {
|
|
|
|
String address = cursor.getString(EMAIL_INDEX);
|
|
|
|
if (address != null) {
|
|
|
|
email.add(address);
|
|
|
|
}
|
2012-04-08 12:32:04 -04:00
|
|
|
|
2012-04-08 19:02:55 -04:00
|
|
|
if (displayName == null) {
|
|
|
|
displayName = cursor.getString(NAME_INDEX);
|
|
|
|
}
|
2012-04-08 12:32:04 -04:00
|
|
|
}
|
2011-03-22 03:06:11 -04:00
|
|
|
|
2012-04-08 19:02:55 -04:00
|
|
|
// Return 'null' if no email addresses have been found
|
2012-04-08 12:32:04 -04:00
|
|
|
if (email.size() == 0) {
|
|
|
|
return null;
|
2012-04-08 12:29:08 -04:00
|
|
|
}
|
2012-04-08 19:02:55 -04:00
|
|
|
|
|
|
|
// Use the first email address found as display name
|
|
|
|
if (displayName == null) {
|
|
|
|
displayName = email.get(0);
|
|
|
|
}
|
|
|
|
|
2012-04-08 19:14:51 -04:00
|
|
|
return new ContactItem(displayName, email);
|
2011-03-22 03:06:11 -04:00
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
Log.e(K9.LOG_TAG, "Failed to get email data", e);
|
|
|
|
} finally {
|
2011-10-20 02:25:27 -04:00
|
|
|
Utility.closeQuietly(cursor);
|
2011-03-22 03:06:11 -04:00
|
|
|
}
|
|
|
|
|
2012-04-08 12:32:04 -04:00
|
|
|
return null;
|
2011-03-22 03:06:11 -04:00
|
|
|
}
|
|
|
|
|
2010-10-30 16:35:49 -04:00
|
|
|
/**
|
|
|
|
* Return a {@link Cursor} instance that can be used to fetch information
|
|
|
|
* about the contact with the given email address.
|
|
|
|
*
|
|
|
|
* @param address The email address to search for.
|
|
|
|
* @return A {@link Cursor} instance that can be used to fetch information
|
|
|
|
* about the contact with the given email address
|
|
|
|
*/
|
2011-02-06 17:09:48 -05:00
|
|
|
private Cursor getContactByAddress(final String address) {
|
2010-10-30 16:35:49 -04:00
|
|
|
final Uri uri = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(address));
|
|
|
|
final Cursor c = mContentResolver.query(
|
|
|
|
uri,
|
|
|
|
PROJECTION,
|
|
|
|
null,
|
|
|
|
null,
|
|
|
|
SORT_ORDER);
|
|
|
|
return c;
|
|
|
|
}
|
2013-02-07 14:01:49 -05:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public Uri getPhotoUri(String address) {
|
|
|
|
Long contactId;
|
|
|
|
try {
|
|
|
|
final Cursor c = getContactByAddress(address);
|
|
|
|
if (c == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
if (!c.moveToFirst()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
contactId = c.getLong(CONTACT_ID_INDEX);
|
|
|
|
} finally {
|
|
|
|
c.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
Cursor cur = mContentResolver.query(
|
|
|
|
ContactsContract.Data.CONTENT_URI,
|
|
|
|
null,
|
|
|
|
ContactsContract.Data.CONTACT_ID + "=" + contactId + " AND "
|
|
|
|
+ ContactsContract.Data.MIMETYPE + "='"
|
|
|
|
+ ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE + "'", null,
|
|
|
|
null);
|
|
|
|
if (cur == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
if (!cur.moveToFirst()) {
|
|
|
|
cur.close();
|
|
|
|
return null; // no photo
|
|
|
|
}
|
|
|
|
// Ok, they have a photo
|
|
|
|
cur.close();
|
|
|
|
Uri person = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId);
|
|
|
|
return Uri.withAppendedPath(person, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
|
|
|
|
} catch (Exception e) {
|
|
|
|
Log.e(K9.LOG_TAG, "Couldn't fetch photo for contact with email " + address, e);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2010-08-14 09:59:33 -04:00
|
|
|
}
|