diff --git a/k9mail/src/main/java/com/fsck/k9/activity/AlternateRecipientAdapter.java b/k9mail/src/main/java/com/fsck/k9/activity/AlternateRecipientAdapter.java index 7e13348b9..cc8c39666 100644 --- a/k9mail/src/main/java/com/fsck/k9/activity/AlternateRecipientAdapter.java +++ b/k9mail/src/main/java/com/fsck/k9/activity/AlternateRecipientAdapter.java @@ -17,11 +17,11 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; -import android.widget.QuickContactBadge; import android.widget.TextView; import com.fsck.k9.R; import com.fsck.k9.activity.compose.RecipientAdapter; +import com.fsck.k9.ui.ContactBadge; import com.fsck.k9.view.RecipientSelectView.Recipient; import com.fsck.k9.view.ThemeUtils; @@ -207,7 +207,7 @@ public class AlternateRecipientAdapter extends BaseAdapter { public final View layoutHeader, layoutItem; public final TextView headerName; public final TextView headerAddressLabel; - public final QuickContactBadge headerPhoto; + public final ContactBadge headerPhoto; public final View headerRemove; public final TextView itemAddress; public final TextView itemAddressLabel; @@ -221,7 +221,7 @@ public class AlternateRecipientAdapter extends BaseAdapter { headerName = (TextView) view.findViewById(R.id.alternate_header_name); headerAddressLabel = (TextView) view.findViewById(R.id.alternate_header_label); - headerPhoto = (QuickContactBadge) view.findViewById(R.id.alternate_contact_photo); + headerPhoto = (ContactBadge) view.findViewById(R.id.alternate_contact_photo); headerRemove = view.findViewById(R.id.alternate_remove); itemAddress = (TextView) view.findViewById(R.id.alternate_address); diff --git a/k9mail/src/main/java/com/fsck/k9/activity/misc/ContactPictureLoader.java b/k9mail/src/main/java/com/fsck/k9/activity/misc/ContactPictureLoader.java index b11a1d2b3..46ca7f895 100644 --- a/k9mail/src/main/java/com/fsck/k9/activity/misc/ContactPictureLoader.java +++ b/k9mail/src/main/java/com/fsck/k9/activity/misc/ContactPictureLoader.java @@ -130,7 +130,7 @@ public class ContactPictureLoader { * Load a contact picture and display it using the supplied {@link ImageView} instance. * *
- * If a picture is found in the cache, it is displayed in the {@code QuickContactBadge}
+ * If a picture is found in the cache, it is displayed in the {@code ContactBadge}
* immediately. Otherwise a {@link ContactPictureRetrievalTask} is started to try to load the
* contact picture in a background thread. Depending on the result the contact picture or a
* fallback picture is then stored in the bitmap cache.
@@ -140,7 +140,7 @@ public class ContactPictureLoader {
* The {@link Address} instance holding the email address that is used to search the
* contacts database.
* @param imageView
- * The {@code QuickContactBadge} instance to receive the picture.
+ * The {@code ContactBadge} instance to receive the picture.
*
* @see #mBitmapCache
* @see #calculateFallbackBitmap(Address)
@@ -242,7 +242,7 @@ public class ContactPictureLoader {
}
}
- // No task associated with the QuickContactBadge, or an existing task was cancelled
+ // No task associated with the ContactBadge, or an existing task was cancelled
return true;
}
diff --git a/k9mail/src/main/java/com/fsck/k9/fragment/MessageListFragment.java b/k9mail/src/main/java/com/fsck/k9/fragment/MessageListFragment.java
index d128f2b1b..8277dc422 100644
--- a/k9mail/src/main/java/com/fsck/k9/fragment/MessageListFragment.java
+++ b/k9mail/src/main/java/com/fsck/k9/fragment/MessageListFragment.java
@@ -62,7 +62,6 @@ import android.widget.AdapterView.OnItemClickListener;
import android.widget.CheckBox;
import android.widget.CursorAdapter;
import android.widget.ListView;
-import android.widget.QuickContactBadge;
import android.widget.TextView;
import android.widget.Toast;
@@ -114,6 +113,7 @@ import com.fsck.k9.search.SearchSpecification;
import com.fsck.k9.search.SearchSpecification.SearchCondition;
import com.fsck.k9.search.SearchSpecification.SearchField;
import com.fsck.k9.search.SqlQueryBuilder;
+import com.fsck.k9.ui.ContactBadge;
public class MessageListFragment extends Fragment implements OnItemClickListener,
@@ -1691,8 +1691,8 @@ public class MessageListFragment extends Fragment implements OnItemClickListener
}
- QuickContactBadge contactBadge =
- (QuickContactBadge) view.findViewById(R.id.contact_badge);
+ ContactBadge contactBadge =
+ (ContactBadge) view.findViewById(R.id.contact_badge);
if (mContactsPictureLoader != null) {
holder.contactBadge = contactBadge;
} else {
@@ -1802,7 +1802,7 @@ public class MessageListFragment extends Fragment implements OnItemClickListener
Utility.setContactForBadge(holder.contactBadge, counterpartyAddress);
/*
* At least in Android 2.2 a different background + padding is used when no
- * email address is available. ListView reuses the views but QuickContactBadge
+ * email address is available. ListView reuses the views but ContactBadge
* doesn't reset the padding, so we do it ourselves.
*/
holder.contactBadge.setPadding(0, 0, 0, 0);
@@ -1960,7 +1960,7 @@ public class MessageListFragment extends Fragment implements OnItemClickListener
public CheckBox flagged;
public CheckBox selected;
public int position = -1;
- public QuickContactBadge contactBadge;
+ public ContactBadge contactBadge;
@Override
public void onClick(View view) {
if (position != -1) {
diff --git a/k9mail/src/main/java/com/fsck/k9/helper/Utility.java b/k9mail/src/main/java/com/fsck/k9/helper/Utility.java
index 66e8874bb..d694298fb 100644
--- a/k9mail/src/main/java/com/fsck/k9/helper/Utility.java
+++ b/k9mail/src/main/java/com/fsck/k9/helper/Utility.java
@@ -14,10 +14,10 @@ import android.text.Editable;
import android.text.TextUtils;
import android.util.Log;
import android.widget.EditText;
-import android.widget.QuickContactBadge;
import android.widget.TextView;
import com.fsck.k9.K9;
+import com.fsck.k9.ui.ContactBadge;
import com.fsck.k9.mail.Address;
import org.apache.james.mime4j.util.MimeUtil;
@@ -483,7 +483,7 @@ public class Utility {
* @param contactBadge the badge to the set the contact for
* @param address the address to look for a contact for.
*/
- public static void setContactForBadge(QuickContactBadge contactBadge,
+ public static void setContactForBadge(ContactBadge contactBadge,
Address address) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
Bundle extraContactInfo = new Bundle();
diff --git a/k9mail/src/main/java/com/fsck/k9/ui/ContactBadge.java b/k9mail/src/main/java/com/fsck/k9/ui/ContactBadge.java
new file mode 100644
index 000000000..b22fb3e32
--- /dev/null
+++ b/k9mail/src/main/java/com/fsck/k9/ui/ContactBadge.java
@@ -0,0 +1,306 @@
+package com.fsck.k9.ui;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.ImageView;
+
+import android.content.AsyncQueryHandler;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Intents;
+import android.provider.ContactsContract.PhoneLookup;
+import android.provider.ContactsContract.QuickContact;
+import android.provider.ContactsContract.RawContacts;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+/**
+ * ContactBadge replaces the android ContactBadge for custom drawing.
+ *
+ * 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 Uri mContactUri;
+ private String mContactEmail;
+ private String mContactPhone;
+ private QueryHandler mQueryHandler;
+ private Bundle mExtras = null;
+
+ protected String[] mExcludeMimes = null;
+
+ static final private int TOKEN_EMAIL_LOOKUP = 0;
+ static final private int TOKEN_PHONE_LOOKUP = 1;
+ static final private int TOKEN_EMAIL_LOOKUP_AND_TRIGGER = 2;
+ static final private int TOKEN_PHONE_LOOKUP_AND_TRIGGER = 3;
+
+ static final private String EXTRA_URI_CONTENT = "uri_content";
+
+ static final String[] EMAIL_LOOKUP_PROJECTION = new String[] {
+ RawContacts.CONTACT_ID,
+ Contacts.LOOKUP_KEY,
+ };
+ static final int EMAIL_ID_COLUMN_INDEX = 0;
+ static final int EMAIL_LOOKUP_STRING_COLUMN_INDEX = 1;
+
+ static final String[] PHONE_LOOKUP_PROJECTION = new String[] {
+ PhoneLookup._ID,
+ PhoneLookup.LOOKUP_KEY,
+ };
+ static final int PHONE_ID_COLUMN_INDEX = 0;
+ static final int PHONE_LOOKUP_STRING_COLUMN_INDEX = 1;
+
+
+ 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);
+ mQueryHandler = new QueryHandler(context.getContentResolver());
+ setOnClickListener(this);
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+ }
+
+ /** This call has no effect anymore, as there is only one QuickContact mode */
+ @SuppressWarnings("unused")
+ public void setMode(int size) {
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ }
+
+ /** True if a contact, an email address or a phone number has been assigned */
+ private boolean isAssigned() {
+ return mContactUri != null || mContactEmail != null || mContactPhone != 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) {
+ mContactUri = contactUri;
+ mContactEmail = null;
+ mContactPhone = 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) {
+ mContactEmail = emailAddress;
+ mExtras = extras;
+ if (!lazyLookup) {
+ mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP, null,
+ Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(mContactEmail)),
+ EMAIL_LOOKUP_PROJECTION, null, null, null);
+ } else {
+ mContactUri = null;
+ onContactUriChanged();
+ }
+ }
+
+
+ /**
+ * Assign a contact based on a phone number. 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 phone number.
+ *
+ * @param phoneNumber The phone number of the contact.
+ * @param lazyLookup If this is true, the lookup query will not be performed
+ * until this view is clicked.
+ */
+
+ public void assignContactFromPhone(String phoneNumber, boolean lazyLookup) {
+ assignContactFromPhone(phoneNumber, lazyLookup, new Bundle());
+ }
+
+ /**
+ * Assign a contact based on a phone number. 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 phone number.
+ *
+ * @param phoneNumber The phone number 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 phone number 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 assignContactFromPhone(String phoneNumber, boolean lazyLookup, Bundle extras) {
+ mContactPhone = phoneNumber;
+ mExtras = extras;
+ if (!lazyLookup) {
+ mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP, null,
+ Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, mContactPhone),
+ PHONE_LOOKUP_PROJECTION, null, null, null);
+ } else {
+ mContactUri = null;
+ onContactUriChanged();
+ }
+ }
+
+ private void onContactUriChanged() {
+ setEnabled(isAssigned());
+ }
+
+ @Override
+ public void onClick(View v) {
+ // If contact has been assigned, mExtras 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 = (mExtras == null) ? new Bundle() : mExtras;
+ if (mContactUri != null) {
+ QuickContact.showQuickContact(getContext(), ContactBadge.this, mContactUri,
+ QuickContact.MODE_LARGE, mExcludeMimes);
+ } else if (mContactEmail != null) {
+ extras.putString(EXTRA_URI_CONTENT, mContactEmail);
+ mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP_AND_TRIGGER, extras,
+ Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(mContactEmail)),
+ EMAIL_LOOKUP_PROJECTION, null, null, null);
+ } else if (mContactPhone != null) {
+ extras.putString(EXTRA_URI_CONTENT, mContactPhone);
+ mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP_AND_TRIGGER, extras,
+ Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, mContactPhone),
+ PHONE_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());
+ }
+
+ /**
+ * Set a list of specific MIME-types to exclude and not display. For
+ * example, this can be used to hide the {@link Contacts#CONTENT_ITEM_TYPE}
+ * profile icon.
+ */
+ public void setExcludeMimes(String[] excludeMimes) {
+ mExcludeMimes = excludeMimes;
+ }
+
+ private class QueryHandler extends AsyncQueryHandler {
+
+ public QueryHandler(ContentResolver cr) {
+ super(cr);
+ }
+
+ @Override
+ protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
+ Uri lookupUri = null;
+ Uri createUri = null;
+ boolean trigger = false;
+ final Bundle extras = (cookie != null) ? (Bundle) cookie : new Bundle();
+ try {
+ switch(token) {
+ case TOKEN_PHONE_LOOKUP_AND_TRIGGER:
+ trigger = true;
+ createUri = Uri.fromParts("tel", extras.getString(EXTRA_URI_CONTENT), null);
+
+ //$FALL-THROUGH$
+ case TOKEN_PHONE_LOOKUP: {
+ if (cursor != null && cursor.moveToFirst()) {
+ long contactId = cursor.getLong(PHONE_ID_COLUMN_INDEX);
+ String lookupKey = cursor.getString(PHONE_LOOKUP_STRING_COLUMN_INDEX);
+ lookupUri = Contacts.getLookupUri(contactId, lookupKey);
+ }
+
+ break;
+ }
+ 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();
+ }
+ }
+
+ mContactUri = lookupUri;
+ onContactUriChanged();
+
+ if (trigger && lookupUri != null) {
+ // Found contact, so trigger QuickContact
+ QuickContact.showQuickContact(getContext(), ContactBadge.this, lookupUri,
+ QuickContact.MODE_LARGE, ContactBadge.this.mExcludeMimes);
+ } 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);
+ }
+ }
+ }
+}
+
diff --git a/k9mail/src/main/java/com/fsck/k9/view/MessageHeader.java b/k9mail/src/main/java/com/fsck/k9/view/MessageHeader.java
index 10b0d3d3b..c823b16b2 100644
--- a/k9mail/src/main/java/com/fsck/k9/view/MessageHeader.java
+++ b/k9mail/src/main/java/com/fsck/k9/view/MessageHeader.java
@@ -23,7 +23,6 @@ import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.CheckBox;
import android.widget.LinearLayout;
-import android.widget.QuickContactBadge;
import android.widget.TextView;
import android.widget.Toast;
@@ -43,6 +42,7 @@ import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.ui.messageview.OnCryptoClickListener;
+import com.fsck.k9.ui.ContactBadge;
public class MessageHeader extends LinearLayout implements OnClickListener, OnLongClickListener {
@@ -70,7 +70,7 @@ public class MessageHeader extends LinearLayout implements OnClickListener, OnLo
private MessageHelper mMessageHelper;
private ContactPictureLoader mContactsPictureLoader;
- private QuickContactBadge mContactBadge;
+ private ContactBadge mContactBadge;
private OnLayoutChangedListener mOnLayoutChangedListener;
private OnCryptoClickListener onCryptoClickListener;
@@ -107,7 +107,7 @@ public class MessageHeader extends LinearLayout implements OnClickListener, OnLo
mCcView = (TextView) findViewById(R.id.cc);
mCcLabel = (TextView) findViewById(R.id.cc_label);
- mContactBadge = (QuickContactBadge) findViewById(R.id.contact_badge);
+ mContactBadge = (ContactBadge) findViewById(R.id.contact_badge);
mSubjectView = (TextView) findViewById(R.id.subject);
mAdditionalHeadersView = (TextView) findViewById(R.id.additional_headers_view);
diff --git a/k9mail/src/main/res/layout/message_list_item.xml b/k9mail/src/main/res/layout/message_list_item.xml
index be40e66f1..221051746 100644
--- a/k9mail/src/main/res/layout/message_list_item.xml
+++ b/k9mail/src/main/res/layout/message_list_item.xml
@@ -39,7 +39,7 @@
-