package com.fsck.k9.ui;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Intents;
import android.provider.ContactsContract.QuickContact;
import android.provider.ContactsContract.RawContacts;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
/**
* ContactBadge replaces the android ContactBadge for custom drawing.
* <p>
* Based on QuickContactBadge:
* https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget/QuickContactBadge.java
*/
public class ContactBadge extends ImageView implements OnClickListener {
private static final int TOKEN_EMAIL_LOOKUP = 0;
private static final int TOKEN_EMAIL_LOOKUP_AND_TRIGGER = 1;
private static final String EXTRA_URI_CONTENT = "uri_content";
private static final String[] EMAIL_LOOKUP_PROJECTION = new String[] {
RawContacts.CONTACT_ID,
Contacts.LOOKUP_KEY,
};
private static final int EMAIL_ID_COLUMN_INDEX = 0;
private static final int EMAIL_LOOKUP_STRING_COLUMN_INDEX = 1;
private Uri contactUri;
private String contactEmail;
private QueryHandler queryHandler;
private Bundle extras = null;
public ContactBadge(Context context) {
this(context, null);
}
public ContactBadge(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ContactBadge(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
queryHandler = new QueryHandler(context.getContentResolver());
setOnClickListener(this);
}
/**
* True if a contact, an email address or a phone number has been assigned
*/
private boolean isAssigned() {
return contactUri != null || contactEmail != null;
}
/**
* Assign the contact uri that this ContactBadge should be associated
* with. Note that this is only used for displaying the QuickContact window and
* won't bind the contact's photo for you. Call {@link #setImageDrawable(Drawable)} to set the
* photo.
*
* @param contactUri
* Either a {@link Contacts#CONTENT_URI} or
* {@link Contacts#CONTENT_LOOKUP_URI} style URI.
*/
public void assignContactUri(Uri contactUri) {
this.contactUri = contactUri;
contactEmail = null;
onContactUriChanged();
}
/**
* Assign a contact based on an email address. This should only be used when
* the contact's URI is not available, as an extra query will have to be
* performed to lookup the URI based on the email.
*
* @param emailAddress
* The email address of the contact.
* @param lazyLookup
* If this is true, the lookup query will not be performed
* until this view is clicked.
*/
public void assignContactFromEmail(String emailAddress, boolean lazyLookup) {
assignContactFromEmail(emailAddress, lazyLookup, null);
}
/**
* Assign a contact based on an email address. This should only be used when
* the contact's URI is not available, as an extra query will have to be
* performed to lookup the URI based on the email.
*
* @param emailAddress
* The email address of the contact.
* @param lazyLookup
* If this is true, the lookup query will not be performed
* until this view is clicked.
* @param extras
* A bundle of extras to populate the contact edit page with if the contact
* is not found and the user chooses to add the email address to an existing contact or
* create a new contact. Uses the same string constants as those found in
* {@link android.provider.ContactsContract.Intents.Insert}
*/
public void assignContactFromEmail(String emailAddress, boolean lazyLookup, Bundle extras) {
contactEmail = emailAddress;
this.extras = extras;
if (!lazyLookup) {
queryHandler.startQuery(TOKEN_EMAIL_LOOKUP, null,
Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(contactEmail)),
EMAIL_LOOKUP_PROJECTION, null, null, null);
} else {
contactUri = null;
onContactUriChanged();
}
}
private void onContactUriChanged() {
setEnabled(isAssigned());
}
@Override
public void onClick(View v) {
// If contact has been assigned, extras should no longer be null, but do a null check
// anyway just in case assignContactFromPhone or Email was called with a null bundle or
// wasn't assigned previously.
final Bundle extras = (this.extras == null) ? new Bundle() : this.extras;
if (contactUri != null) {
QuickContact.showQuickContact(getContext(), ContactBadge.this, contactUri,
QuickContact.MODE_LARGE, null);
} else if (contactEmail != null) {
extras.putString(EXTRA_URI_CONTENT, contactEmail);
queryHandler.startQuery(TOKEN_EMAIL_LOOKUP_AND_TRIGGER, extras,
Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(contactEmail)),
EMAIL_LOOKUP_PROJECTION, null, null, null);
}
}
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(ContactBadge.class.getName());
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(ContactBadge.class.getName());
}
private class QueryHandler extends AsyncQueryHandler {
QueryHandler(ContentResolver cr) {
super(cr);
}
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
Uri lookupUri = null;
Uri createUri = null;
boolean trigger = false;
Bundle extras = (cookie != null) ? (Bundle) cookie : new Bundle();
try {
switch (token) {
case TOKEN_EMAIL_LOOKUP_AND_TRIGGER:
trigger = true;
createUri = Uri.fromParts("mailto",
extras.getString(EXTRA_URI_CONTENT), null);
//$FALL-THROUGH$
case TOKEN_EMAIL_LOOKUP: {
if (cursor != null && cursor.moveToFirst()) {
long contactId = cursor.getLong(EMAIL_ID_COLUMN_INDEX);
String lookupKey = cursor.getString(EMAIL_LOOKUP_STRING_COLUMN_INDEX);
lookupUri = Contacts.getLookupUri(contactId, lookupKey);
}
break;
}
}
} finally {
if (cursor != null) {
cursor.close();
}
}
contactUri = lookupUri;
onContactUriChanged();
if (trigger && lookupUri != null) {
// Found contact, so trigger QuickContact
QuickContact.showQuickContact(
getContext(), ContactBadge.this, lookupUri, QuickContact.MODE_LARGE, null);
} else if (createUri != null) {
// Prompt user to add this person to contacts
final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, createUri);
extras.remove(EXTRA_URI_CONTENT);
intent.putExtras(extras);
getContext().startActivity(intent);
}
}
}
}