Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e814b5dc authored by cketti's avatar cketti
Browse files

Extract code to draw fallback contact pictures to a separate class

parent c787845e
Loading
Loading
Loading
Loading
+7 −65
Original line number Diff line number Diff line
@@ -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);
        }

+69 −0
Original line number Diff line number Diff line
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()
        )
    }
}
+0 −95
Original line number Diff line number Diff line
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);
    }
}