package com.aberdyne.droidnavi.client;
import java.io.IOException;
import java.io.InputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pctelelog.ContactInfo;
import pctelelog.ContactInfo.Email;
import pctelelog.ContactInfo.Photo;
import pctelelog.PhoneNumber;
import pctelelog.ContactInfo.Name;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.BaseColumns;
import android.provider.ContactsContract;
import android.provider.ContactsContract.PhoneLookup;
import android.util.Base64;
public class ContactInfoPoller {
private static final Logger logger = LoggerFactory.getLogger(ContactInfoPoller.class);
protected ContactInfoPoller() {}
/**
* Checks if contact exists.
*
* This check is not thorough and really only looks if
* there is an associated name with a number in the contact log.
*
* @param context The current context
* @param number A number to check the contact DB for
* @return True if info/a name was found. False otherwise.
*/
static public boolean hasInfo(Context context, String number) {
ContactInfo info = pollInfo(context, number);
if(info.getName().equals(Name.UNKNOWN))
return false;
else
return true;
}
static public ContactInfo pollInfo(Context context, String number) {
logger.trace("ENTRY ContactInfoPoller.pollInfo({}, {})", context, number);
// Without a context, polling contacts isn't possible
if(context == null) {
logger.trace("EXIT ContactInfoPoller.pollInfo: null");
return null;
}
// Retrieve the lookup URI to the contact in the database
Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(number));
if(contactUri == null) {
return new ContactInfo(new PhoneNumber(number));
}
// Get a cursor to the contact's entry
Cursor cursor; // Cursor object
String mime; // MIME type
int mimeIdx; // Index of MIMETYPE column
int nameIdx; // Index of DISPLAY_NAME column
cursor = context.getContentResolver().query(contactUri,
new String[] { ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.PHOTO_ID,
BaseColumns._ID },
null, null, null);
/* Defaults */
Name name = Name.UNKNOWN;
Email email = Email.NO_EMAIL;
PhoneNumber phoneNumber = new PhoneNumber(number);
Photo photo = null;
if(cursor.moveToFirst()) {
// Get Display Name
nameIdx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
String displayName = cursor.getString(nameIdx);
// Get Contact ID
int contactidIdx = cursor.getColumnIndex(BaseColumns._ID);
long contactId = cursor.getLong(contactidIdx);
// Get Photo ID
int photoidIdx = cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_ID);
int photoId = cursor.getInt(photoidIdx);
// Setup for further queries
String[] projection = {
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.Data.DATA1, // Display name (StructuredName type) / Email
ContactsContract.Contacts.Data.DATA2, // First name (StructuredName type)
ContactsContract.Contacts.Data.DATA3, // Last name (StructuredName type)
ContactsContract.Contacts.Data.MIMETYPE
};
cursor.close(); // Release resources
// Query for data matching display name
cursor = context.getContentResolver().query(
ContactsContract.Data.CONTENT_URI,
projection,
ContactsContract.Data.DISPLAY_NAME + "= ?",
new String[] { displayName },
null);
if(cursor.moveToFirst()) {
mimeIdx = cursor.getColumnIndex(ContactsContract.Contacts.Data.MIMETYPE);
// Check MIME type and store data
do {
mime = cursor.getString(mimeIdx);
if(ContactsContract.CommonDataKinds.Email.
CONTENT_ITEM_TYPE.equalsIgnoreCase(mime)) {
email = getEmail(cursor);
}
else if(ContactsContract.CommonDataKinds.StructuredName
.CONTENT_ITEM_TYPE.equalsIgnoreCase(mime)) {
name = getName(cursor);
}
} while(cursor.moveToNext());
// Try to get the photo
photo = ContactInfoPoller.loadContactPhoto(context.getContentResolver(), contactId, photoId);
}
cursor.close(); // Release resources
}
ContactInfo info = new ContactInfo(name, phoneNumber, email, photo);
logger.trace("EXIT ContactInfoPoller.pollInfo: {}", info);
return info;
}
static private Name getName(Cursor cursor) {
int dataIdx = cursor.getColumnIndex(ContactsContract.Contacts.Data.DATA1);
String displayName = cursor.getString(dataIdx);
dataIdx = cursor.getColumnIndex(ContactsContract.Contacts.Data.DATA2);
String firstName = cursor.getString(dataIdx);
dataIdx = cursor.getColumnIndex(ContactsContract.Contacts.Data.DATA3);
String lastName = cursor.getString(dataIdx);
return new Name(displayName, firstName, lastName);
}
static private Email getEmail(Cursor cursor) {
int dataIdx = cursor.getColumnIndex(ContactsContract.Contacts.Data.DATA1);
String emailStr = cursor.getString(dataIdx);
return new Email(emailStr);
}
/**
* Grab the Photo from the Contact database.
*
* This will attempt two kinds of searches for the contact Photo. First
* it will try to find the photo using the Contact ID and if that fails
* then it will attempt to find it using the Photo Id.
* @param cr Content Rsolver to use for querying database
* @param id A content id to look for a photo for
* @param photo_id A photo id for a contact
* @return The photo for the contact if it succeeds. Returns null if it fails
* to find anything.
*/
public static Photo loadContactPhoto(ContentResolver cr, long id,long photo_id)
{
Photo ret = null;
/* Attempt using Contact_ID */
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id);
InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(cr, uri);
if (input != null)
{
byte[] data = null;
try {
int size = input.available();
logger.debug("PHOTO: size {}", Integer.toString(size));
data = new byte[size];
input.read(data);
String encodedBase64 = new String(Base64.encode(data, Base64.NO_WRAP));
ret = Photo.androidConstructor(encodedBase64);
} catch (IOException e) {
logger.error(e.toString());
}
return ret;
}
else
{
logger.debug("PHOTO: first try failed to load photo");
}
/* Attempt using Photo_ID */
byte[] photoBytes = null;
Uri photoUri = ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, photo_id);
Cursor c = cr.query(photoUri, new String[] {ContactsContract.CommonDataKinds.Photo.PHOTO}, null, null, null);
try
{
if (c.moveToFirst())
photoBytes = c.getBlob(0);
} catch (Exception e) {
logger.error("Failed to get photo data blob.");
}
c.close();
if (photoBytes != null) {
String encodedBase64 = new String(Base64.encode(photoBytes, Base64.NO_WRAP));
ret = Photo.androidConstructor(encodedBase64);
return ret;
}
else
logger.debug("PHOTO: second try also failed");
return null;
}
}