Replace QuickContactBadge with custom widget

This commit is contained in:
madRat 2016-08-26 15:06:30 +03:00 committed by Vincent Breitmoser
parent e70295efec
commit 923d91b012
9 changed files with 326 additions and 20 deletions

View file

@ -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);

View file

@ -130,7 +130,7 @@ public class ContactPictureLoader {
* Load a contact picture and display it using the supplied {@link ImageView} instance.
*
* <p>
* 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;
}

View file

@ -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) {

View file

@ -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();

View file

@ -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);
}
}
}
}

View file

@ -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);

View file

@ -39,7 +39,7 @@
</LinearLayout>
<QuickContactBadge
<com.fsck.k9.ui.ContactBadge
android:id="@+id/contact_badge"
android:layout_marginRight="8dip"
android:layout_marginTop="4dip"

View file

@ -48,7 +48,7 @@
android:layout_height="wrap_content"
android:orientation="vertical" >
<QuickContactBadge
<com.fsck.k9.ui.ContactBadge
android:id="@+id/contact_badge"
android:layout_width="40dp"
android:layout_height="40dp"

View file

@ -16,7 +16,7 @@
android:id="@+id/alternate_container_header"
>
<QuickContactBadge
<com.fsck.k9.ui.ContactBadge
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_marginLeft="12dp"