Extract code to draw fallback contact pictures to a separate class

This commit is contained in:
cketti 2018-07-19 14:29:56 +02:00
parent c787845ebe
commit e814b5dca0
3 changed files with 76 additions and 160 deletions

View file

@ -8,13 +8,8 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
import android.widget.ImageView;
@ -35,6 +30,7 @@ import com.bumptech.glide.load.resource.transcode.BitmapToGlideDrawableTranscode
import com.bumptech.glide.request.FutureTarget;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.fsck.k9.contacts.ContactLetterBitmapCreator;
import com.fsck.k9.contacts.ContactLetterExtractor;
import com.fsck.k9.helper.Contacts;
import com.fsck.k9.mail.Address;
@ -47,35 +43,12 @@ public class ContactPictureLoader {
*/
private static final int PICTURE_SIZE = 40;
private static final ContactLetterExtractor CONTACT_LETTER_EXTRACTOR = new ContactLetterExtractor();
private final Context context;
private final ContactLetterBitmapCreator contactLetterBitmapCreator;
private Contacts mContactsHelper;
private int mPictureSizeInPx;
private int mDefaultBackgroundColor;
/**
* @see <a href="http://developer.android.com/design/style/color.html">Color palette used</a>
*/
private final static int CONTACT_DUMMY_COLORS_ARGB[] = {
0xff33B5E5,
0xffAA66CC,
0xff99CC00,
0xffFFBB33,
0xffFF4444,
0xff0099CC,
0xff9933CC,
0xff669900,
0xffFF8800,
0xffCC0000
};
@VisibleForTesting
protected static String calcUnknownContactLetter(Address address) {
return CONTACT_LETTER_EXTRACTOR.extractContactLetter(address);
}
/**
* Constructor.
@ -94,8 +67,8 @@ public class ContactPictureLoader {
float scale = resources.getDisplayMetrics().density;
mPictureSizeInPx = (int) (PICTURE_SIZE * scale);
mDefaultBackgroundColor = defaultBackgroundColor;
ContactLetterExtractor contactLetterExtractor = new ContactLetterExtractor();
contactLetterBitmapCreator = new ContactLetterBitmapCreator(contactLetterExtractor, defaultBackgroundColor);
}
public void loadContactPicture(final Address address, final ImageView imageView) {
@ -188,39 +161,6 @@ public class ContactPictureLoader {
return loadIgnoringErors(bitmapTarget);
}
private int calcUnknownContactColor(Address address) {
if (mDefaultBackgroundColor != 0) {
return mDefaultBackgroundColor;
}
int val = address.hashCode();
int colorIndex = (val & Integer.MAX_VALUE) % CONTACT_DUMMY_COLORS_ARGB.length;
return CONTACT_DUMMY_COLORS_ARGB[colorIndex];
}
private Bitmap drawTextAndBgColorOnBitmap(Bitmap bitmap, FallbackGlideParams params) {
Canvas canvas = new Canvas(bitmap);
int rgb = calcUnknownContactColor(params.address);
bitmap.eraseColor(rgb);
String letter = calcUnknownContactLetter(params.address);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Style.FILL);
paint.setARGB(255, 255, 255, 255);
paint.setTextSize(mPictureSizeInPx * 3 / 4); // just scale this down a bit
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 bitmap;
}
private class FallbackGlideBitmapDecoder implements ResourceDecoder<FallbackGlideParams, Bitmap> {
private final Context context;
@ -235,7 +175,9 @@ public class ContactPictureLoader {
if (bitmap == null) {
bitmap = Bitmap.createBitmap(mPictureSizeInPx, mPictureSizeInPx, Bitmap.Config.ARGB_8888);
}
drawTextAndBgColorOnBitmap(bitmap, source);
Address address = source.address;
contactLetterBitmapCreator.drawBitmap(bitmap, mPictureSizeInPx, address);
return BitmapResource.obtain(bitmap, pool);
}

View file

@ -0,0 +1,69 @@
package com.fsck.k9.contacts
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import com.fsck.k9.mail.Address
/**
* Draw a `Bitmap` containing the "contact letter" obtained by [ContactLetterExtractor].
*
* @param defaultBackgroundColor The ARGB value to be used as background color for the fallback picture. `0` to use a
* dynamically calculated background color.
*/
class ContactLetterBitmapCreator(
private val letterExtractor: ContactLetterExtractor,
private val defaultBackgroundColor: Int
) {
fun drawBitmap(bitmap: Bitmap, pictureSizeInPx: Int, address: Address): Bitmap {
val canvas = Canvas(bitmap)
val backgroundColor = calcUnknownContactColor(address)
bitmap.eraseColor(backgroundColor)
val letter = letterExtractor.extractContactLetter(address)
val paint = Paint().apply {
isAntiAlias = true
style = Paint.Style.FILL
setARGB(255, 255, 255, 255)
textSize = (pictureSizeInPx * 3 / 4).toFloat() // just scale this down a bit
}
val rect = Rect()
paint.getTextBounds(letter, 0, 1, rect)
val width = paint.measureText(letter)
canvas.drawText(letter,
pictureSizeInPx / 2f - width / 2f,
pictureSizeInPx / 2f + rect.height() / 2f, paint)
return bitmap
}
private fun calcUnknownContactColor(address: Address): Int {
if (defaultBackgroundColor != 0) {
return defaultBackgroundColor
}
val hash = address.hashCode()
val colorIndex = (hash and Integer.MAX_VALUE) % BACKGROUND_COLORS.size
return BACKGROUND_COLORS[colorIndex]
}
companion object {
private val BACKGROUND_COLORS = intArrayOf(
0xff33B5E5L.toInt(),
0xffAA66CCL.toInt(),
0xff99CC00L.toInt(),
0xffFFBB33L.toInt(),
0xffFF4444L.toInt(),
0xff0099CCL.toInt(),
0xff9933CCL.toInt(),
0xff669900L.toInt(),
0xffFF8800L.toInt(),
0xffCC0000L.toInt()
)
}
}

View file

@ -1,95 +0,0 @@
package com.fsck.k9.activity.misc;
import com.fsck.k9.RobolectricTest;
import com.fsck.k9.mail.Address;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class ContactPictureLoaderTest extends RobolectricTest {
@Test
public void calcUnknownContactLetter_withNoNameUsesAddress() {
Address address = new Address("<c@d.com>");
String result = ContactPictureLoader.calcUnknownContactLetter(address);
assertEquals("C", result);
}
@Test
public void calcUnknownContactLetter_withAsciiName() {
Address address = new Address("abcd <a@b.com>");
String result = ContactPictureLoader.calcUnknownContactLetter(address);
assertEquals("A", result);
}
@Test
public void calcUnknownContactLetter_withLstroke() {
Address address = new Address("Łatynka <a@b.com>");
String result = ContactPictureLoader.calcUnknownContactLetter(address);
assertEquals("Ł", result);
}
@Test
public void calcUnknownContactLetter_withChinese() {
Address address = new Address("千里之行﹐始于足下 <a@b.com>");
String result = ContactPictureLoader.calcUnknownContactLetter(address);
assertEquals("", result);
}
@Test
public void calcUnknownContactLetter_withCombinedGlyphs() {
Address address = new Address("\u0061\u0300 <a@b.com>");
String result = ContactPictureLoader.calcUnknownContactLetter(address);
assertEquals("\u0041\u0300", result);
}
@Test
public void calcUnknownContactLetter_withSurrogatePair() {
Address address = new Address("\uD800\uDFB5 <a@b.com>");
String result = ContactPictureLoader.calcUnknownContactLetter(address);
assertEquals("\uD800\uDFB5", result);
}
@Test
public void calcUnknownContactLetter_ignoresSpace() {
Address address = new Address(" abcd <a@b.com>");
String result = ContactPictureLoader.calcUnknownContactLetter(address);
assertEquals("A", result);
}
@Test
public void calcUnknownContactLetter_ignoresUsePunctuation() {
Address address = new Address("-a <a@b.com>");
String result = ContactPictureLoader.calcUnknownContactLetter(address);
assertEquals("A", result);
}
@Test
public void calcUnknownContactLetter_ignoresMatchEmoji() {
Address address = new Address("\uD83D\uDE00 <a@b.com>");
String result = ContactPictureLoader.calcUnknownContactLetter(address);
assertEquals("?", result);
}
}