mirror of
https://github.com/moparisthebest/k-9
synced 2024-12-25 09:08:49 -05:00
GMail-app-style generated colorful one-letter contact pictures for pictureless contacts
This commit is contained in:
parent
b0c9ae0d88
commit
3feaeb6903
@ -5,6 +5,8 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.concurrent.RejectedExecutionException;
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
@ -12,6 +14,9 @@ import android.content.Context;
|
|||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@ -20,6 +25,7 @@ import android.os.Build;
|
|||||||
import android.support.v4.util.LruCache;
|
import android.support.v4.util.LruCache;
|
||||||
import android.widget.QuickContactBadge;
|
import android.widget.QuickContactBadge;
|
||||||
import com.fsck.k9.helper.Contacts;
|
import com.fsck.k9.helper.Contacts;
|
||||||
|
import com.fsck.k9.mail.Address;
|
||||||
|
|
||||||
public class ContactPictureLoader {
|
public class ContactPictureLoader {
|
||||||
/**
|
/**
|
||||||
@ -41,7 +47,6 @@ public class ContactPictureLoader {
|
|||||||
private ContentResolver mContentResolver;
|
private ContentResolver mContentResolver;
|
||||||
private Resources mResources;
|
private Resources mResources;
|
||||||
private Contacts mContactsHelper;
|
private Contacts mContactsHelper;
|
||||||
private Bitmap mDefaultPicture;
|
|
||||||
private int mPictureSizeInPx;
|
private int mPictureSizeInPx;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,7 +73,6 @@ public class ContactPictureLoader {
|
|||||||
mContentResolver = appContext.getContentResolver();
|
mContentResolver = appContext.getContentResolver();
|
||||||
mResources = appContext.getResources();
|
mResources = appContext.getResources();
|
||||||
mContactsHelper = Contacts.getInstance(appContext);
|
mContactsHelper = Contacts.getInstance(appContext);
|
||||||
mDefaultPicture = BitmapFactory.decodeResource(mResources, defaultPictureResource);
|
|
||||||
|
|
||||||
float scale = mResources.getDisplayMetrics().density;
|
float scale = mResources.getDisplayMetrics().density;
|
||||||
mPictureSizeInPx = (int) (PICTURE_SIZE * scale);
|
mPictureSizeInPx = (int) (PICTURE_SIZE * scale);
|
||||||
@ -115,7 +119,8 @@ public class ContactPictureLoader {
|
|||||||
* @see #mBitmapCache
|
* @see #mBitmapCache
|
||||||
* @see #mUnknownContactsCache
|
* @see #mUnknownContactsCache
|
||||||
*/
|
*/
|
||||||
public void loadContactPicture(String email, QuickContactBadge badge) {
|
public void loadContactPicture(Address address, QuickContactBadge badge) {
|
||||||
|
String email = address.getAddress();
|
||||||
Bitmap bitmap = getBitmapFromCache(email);
|
Bitmap bitmap = getBitmapFromCache(email);
|
||||||
if (bitmap != null) {
|
if (bitmap != null) {
|
||||||
// The picture was found in the bitmap cache
|
// The picture was found in the bitmap cache
|
||||||
@ -123,22 +128,73 @@ public class ContactPictureLoader {
|
|||||||
} else if (isEmailInUnknownContactsCache(email)) {
|
} else if (isEmailInUnknownContactsCache(email)) {
|
||||||
// This email address doesn't belong to a contact we have a picture for. Use the
|
// This email address doesn't belong to a contact we have a picture for. Use the
|
||||||
// default picture.
|
// default picture.
|
||||||
badge.setImageBitmap(mDefaultPicture);
|
badge.setImageBitmap(calculateFallbackBitmap(address));
|
||||||
} else if (cancelPotentialWork(email, badge)) {
|
} else if (cancelPotentialWork(email, badge)) {
|
||||||
// Query the contacts database in a background thread and try to load the contact
|
// Query the contacts database in a background thread and try to load the contact
|
||||||
// picture, if there is one.
|
// picture, if there is one.
|
||||||
ContactPictureRetrievalTask task = new ContactPictureRetrievalTask(badge);
|
ContactPictureRetrievalTask task = new ContactPictureRetrievalTask(badge);
|
||||||
AsyncDrawable asyncDrawable = new AsyncDrawable(mResources, mDefaultPicture, task);
|
AsyncDrawable asyncDrawable = new AsyncDrawable(mResources, calculateFallbackBitmap(address), task);
|
||||||
badge.setImageDrawable(asyncDrawable);
|
badge.setImageDrawable(asyncDrawable);
|
||||||
try {
|
try {
|
||||||
task.exec(email);
|
task.exec(address.getAddress(), address.getPersonal());
|
||||||
} catch (RejectedExecutionException e) {
|
} catch (RejectedExecutionException e) {
|
||||||
// We flooded the thread pool queue... fall back to using the default picture
|
// We flooded the thread pool queue... fall back to using the default picture
|
||||||
badge.setImageBitmap(mDefaultPicture);
|
badge.setImageBitmap(calculateFallbackBitmap(address));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int calcUnknownContactColor(Address address) {
|
||||||
|
int val = address.getAddress().toLowerCase().hashCode();
|
||||||
|
int rgb =
|
||||||
|
(0xff) << 24 |
|
||||||
|
(~val & 0xff) << 16 |
|
||||||
|
(val & 0xff) << 8 |
|
||||||
|
(val>>>8 & 0xff);
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private char calcUnknownContactLetter(Address address) {
|
||||||
|
String letter = "";
|
||||||
|
Pattern p = Pattern.compile("[^a-zA-Z]*([a-zA-Z]).*");
|
||||||
|
String str = address.getPersonal() != null ? address.getPersonal() : address.getAddress();
|
||||||
|
Matcher m = p.matcher(str);
|
||||||
|
if (m.matches()) {
|
||||||
|
letter = m.group(1).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
return letter.length() == 0 ? 'K' : letter.charAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Calculates a bitmap with a color and a capital letter for
|
||||||
|
* contacts without picture.
|
||||||
|
* */
|
||||||
|
private Bitmap calculateFallbackBitmap(Address address) {
|
||||||
|
Bitmap result = Bitmap.createBitmap(mPictureSizeInPx, mPictureSizeInPx, Bitmap.Config.ARGB_8888);
|
||||||
|
|
||||||
|
Canvas canvas = new Canvas(result);
|
||||||
|
|
||||||
|
int rgb = calcUnknownContactColor(address);
|
||||||
|
result.eraseColor(rgb);
|
||||||
|
|
||||||
|
String letter = Character.toString(calcUnknownContactLetter(address));
|
||||||
|
|
||||||
|
Paint paint = new Paint();
|
||||||
|
paint.setAntiAlias(true);
|
||||||
|
paint.setStyle(Paint.Style.FILL);
|
||||||
|
paint.setARGB(255, 255, 255, 255);
|
||||||
|
paint.setFakeBoldText(true);
|
||||||
|
paint.setTextSize(mPictureSizeInPx);
|
||||||
|
Rect rect = new Rect();
|
||||||
|
paint.getTextBounds(letter, 0, 1, rect);
|
||||||
|
float width = paint.measureText(letter);
|
||||||
|
canvas.drawText(letter,
|
||||||
|
mPictureSizeInPx/2f-width/2f,
|
||||||
|
mPictureSizeInPx/2f+rect.height()/2f, paint);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private void addBitmapToCache(String key, Bitmap bitmap) {
|
private void addBitmapToCache(String key, Bitmap bitmap) {
|
||||||
if (getBitmapFromCache(key) == null) {
|
if (getBitmapFromCache(key) == null) {
|
||||||
mBitmapCache.put(key, bitmap);
|
mBitmapCache.put(key, bitmap);
|
||||||
@ -176,7 +232,7 @@ public class ContactPictureLoader {
|
|||||||
final ContactPictureRetrievalTask task = getContactPictureRetrievalTask(badge);
|
final ContactPictureRetrievalTask task = getContactPictureRetrievalTask(badge);
|
||||||
|
|
||||||
if (task != null && email != null) {
|
if (task != null && email != null) {
|
||||||
String emailFromTask = task.getEmail();
|
String emailFromTask = task.getAddress().getAddress();
|
||||||
if (!email.equals(emailFromTask)) {
|
if (!email.equals(emailFromTask)) {
|
||||||
// Cancel previous task
|
// Cancel previous task
|
||||||
task.cancel(true);
|
task.cancel(true);
|
||||||
@ -208,7 +264,7 @@ public class ContactPictureLoader {
|
|||||||
*/
|
*/
|
||||||
class ContactPictureRetrievalTask extends AsyncTask<String, Void, Bitmap> {
|
class ContactPictureRetrievalTask extends AsyncTask<String, Void, Bitmap> {
|
||||||
private final WeakReference<QuickContactBadge> mQuickContactBadgeReference;
|
private final WeakReference<QuickContactBadge> mQuickContactBadgeReference;
|
||||||
private String mEmail;
|
private Address mAddress;
|
||||||
|
|
||||||
ContactPictureRetrievalTask(QuickContactBadge badge) {
|
ContactPictureRetrievalTask(QuickContactBadge badge) {
|
||||||
mQuickContactBadgeReference = new WeakReference<QuickContactBadge>(badge);
|
mQuickContactBadgeReference = new WeakReference<QuickContactBadge>(badge);
|
||||||
@ -222,14 +278,15 @@ public class ContactPictureLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEmail() {
|
public Address getAddress() {
|
||||||
return mEmail;
|
return mAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Bitmap doInBackground(String... args) {
|
protected Bitmap doInBackground(String... args) {
|
||||||
String email = args[0];
|
String email = args[0];
|
||||||
mEmail = email;
|
String personal = args[1];
|
||||||
|
mAddress = new Address(email, personal);
|
||||||
final Uri x = mContactsHelper.getPhotoUri(email);
|
final Uri x = mContactsHelper.getPhotoUri(email);
|
||||||
Bitmap bitmap = null;
|
Bitmap bitmap = null;
|
||||||
if (x != null) {
|
if (x != null) {
|
||||||
@ -256,7 +313,7 @@ public class ContactPictureLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bitmap == null) {
|
if (bitmap == null) {
|
||||||
bitmap = mDefaultPicture;
|
bitmap = calculateFallbackBitmap(mAddress);
|
||||||
|
|
||||||
// Remember that we don't have a contact picture for this email address
|
// Remember that we don't have a contact picture for this email address
|
||||||
addEmailToUnknownContactsCache(email);
|
addEmailToUnknownContactsCache(email);
|
||||||
|
@ -1875,15 +1875,15 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
|
|||||||
CharSequence displayName = mMessageHelper.getDisplayName(account, fromAddrs, toAddrs);
|
CharSequence displayName = mMessageHelper.getDisplayName(account, fromAddrs, toAddrs);
|
||||||
CharSequence displayDate = DateUtils.getRelativeTimeSpanString(context, cursor.getLong(DATE_COLUMN));
|
CharSequence displayDate = DateUtils.getRelativeTimeSpanString(context, cursor.getLong(DATE_COLUMN));
|
||||||
|
|
||||||
String counterpartyAddress = null;
|
Address counterpartyAddress = null;
|
||||||
if (fromMe) {
|
if (fromMe) {
|
||||||
if (toAddrs.length > 0) {
|
if (toAddrs.length > 0) {
|
||||||
counterpartyAddress = toAddrs[0].getAddress();
|
counterpartyAddress = toAddrs[0];
|
||||||
} else if (ccAddrs.length > 0) {
|
} else if (ccAddrs.length > 0) {
|
||||||
counterpartyAddress = ccAddrs[0].getAddress();
|
counterpartyAddress = ccAddrs[0];
|
||||||
}
|
}
|
||||||
} else if (fromAddrs.length > 0) {
|
} else if (fromAddrs.length > 0) {
|
||||||
counterpartyAddress = fromAddrs[0].getAddress();
|
counterpartyAddress = fromAddrs[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
int threadCount = (mThreadedList) ? cursor.getInt(THREAD_COUNT_COLUMN) : 0;
|
int threadCount = (mThreadedList) ? cursor.getInt(THREAD_COUNT_COLUMN) : 0;
|
||||||
@ -1923,7 +1923,7 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
|
|||||||
holder.position = cursor.getPosition();
|
holder.position = cursor.getPosition();
|
||||||
|
|
||||||
if (holder.contactBadge != null) {
|
if (holder.contactBadge != null) {
|
||||||
holder.contactBadge.assignContactFromEmail(counterpartyAddress, true);
|
holder.contactBadge.assignContactFromEmail(counterpartyAddress.getAddress(), true);
|
||||||
if (counterpartyAddress != null) {
|
if (counterpartyAddress != null) {
|
||||||
/*
|
/*
|
||||||
* At least in Android 2.2 a different background + padding is used when no
|
* At least in Android 2.2 a different background + padding is used when no
|
||||||
|
@ -226,15 +226,15 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
|||||||
Address[] ccAddrs = message.getRecipients(Message.RecipientType.CC);
|
Address[] ccAddrs = message.getRecipients(Message.RecipientType.CC);
|
||||||
boolean fromMe = mMessageHelper.toMe(account, fromAddrs);
|
boolean fromMe = mMessageHelper.toMe(account, fromAddrs);
|
||||||
|
|
||||||
String counterpartyAddress = null;
|
Address counterpartyAddress = null;
|
||||||
if (fromMe) {
|
if (fromMe) {
|
||||||
if (toAddrs.length > 0) {
|
if (toAddrs.length > 0) {
|
||||||
counterpartyAddress = toAddrs[0].getAddress();
|
counterpartyAddress = toAddrs[0];
|
||||||
} else if (ccAddrs.length > 0) {
|
} else if (ccAddrs.length > 0) {
|
||||||
counterpartyAddress = ccAddrs[0].getAddress();
|
counterpartyAddress = ccAddrs[0];
|
||||||
}
|
}
|
||||||
} else if (fromAddrs.length > 0) {
|
} else if (fromAddrs.length > 0) {
|
||||||
counterpartyAddress = fromAddrs[0].getAddress();
|
counterpartyAddress = fromAddrs[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -275,7 +275,7 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
|||||||
mDateView.setText(dateTime);
|
mDateView.setText(dateTime);
|
||||||
|
|
||||||
if (K9.showContactPicture()) {
|
if (K9.showContactPicture()) {
|
||||||
mContactBadge.assignContactFromEmail(counterpartyAddress, true);
|
mContactBadge.assignContactFromEmail(counterpartyAddress.getAddress(), true);
|
||||||
if (counterpartyAddress != null) {
|
if (counterpartyAddress != null) {
|
||||||
mContactsPictureLoader.loadContactPicture(counterpartyAddress, mContactBadge);
|
mContactsPictureLoader.loadContactPicture(counterpartyAddress, mContactBadge);
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user