am a91c4a68: am 5bd692e8: am 62e7c5a9: am c12da4a5: Prevent contact icons from cropping

* commit 'a91c4a68de13cb93e131ad8cbb5cef83ecfc8759':
  Prevent contact icons from cropping
diff --git a/src/com/android/mail/bitmap/AbstractAvatarDrawable.java b/src/com/android/mail/bitmap/AbstractAvatarDrawable.java
new file mode 100644
index 0000000..4f65c84
--- /dev/null
+++ b/src/com/android/mail/bitmap/AbstractAvatarDrawable.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.mail.bitmap;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
+
+import com.android.bitmap.BitmapCache;
+import com.android.bitmap.RequestKey;
+import com.android.bitmap.ReusableBitmap;
+
+import com.android.mail.R;
+import com.android.mail.bitmap.ContactResolver.ContactDrawableInterface;
+
+/**
+ * A drawable that encapsulates all the functionality needed to display a contact image,
+ * including request creation/cancelling and data unbinding/re-binding.
+ * <p>
+ * The actual contact resolving and decoding is handled by {@link ContactResolver}.
+ * <p>
+ * For better performance, you should define a cache with {@link #setBitmapCache(BitmapCache)}.
+ */
+public abstract class AbstractAvatarDrawable extends Drawable implements ContactDrawableInterface {
+    protected final Resources mResources;
+
+    private BitmapCache mCache;
+    private ContactResolver mContactResolver;
+
+    protected ContactRequest mContactRequest;
+    protected ReusableBitmap mBitmap;
+
+    protected final float mBorderWidth;
+    protected final Paint mBitmapPaint;
+    protected final Paint mBorderPaint;
+    protected final Matrix mMatrix;
+
+    private int mDecodedWidth;
+    private int mDecodedHeight;
+
+    public AbstractAvatarDrawable(final Resources res) {
+        mResources = res;
+
+        mBitmapPaint = new Paint();
+        mBitmapPaint.setAntiAlias(true);
+        mBitmapPaint.setFilterBitmap(true);
+        mBitmapPaint.setDither(true);
+
+        mBorderWidth = res.getDimensionPixelSize(R.dimen.avatar_border_width);
+
+        mBorderPaint = new Paint();
+        mBorderPaint.setColor(Color.TRANSPARENT);
+        mBorderPaint.setStyle(Paint.Style.STROKE);
+        mBorderPaint.setStrokeWidth(mBorderWidth);
+        mBorderPaint.setAntiAlias(true);
+
+        mMatrix = new Matrix();
+    }
+
+    public void setBitmapCache(final BitmapCache cache) {
+        mCache = cache;
+    }
+
+    public void setContactResolver(final ContactResolver contactResolver) {
+        mContactResolver = contactResolver;
+    }
+
+    @Override
+    public void draw(final Canvas canvas) {
+        final Rect bounds = getBounds();
+        if (!isVisible() || bounds.isEmpty()) {
+            return;
+        }
+
+        if (mBitmap != null && mBitmap.bmp != null) {
+            // Draw sender image.
+            drawBitmap(mBitmap.bmp, mBitmap.getLogicalWidth(), mBitmap.getLogicalHeight(), canvas);
+        } else {
+            // Draw the default image
+            drawDefaultAvatar(canvas);
+        }
+    }
+
+    protected abstract void drawDefaultAvatar(Canvas canvas);
+
+    /**
+     * Draw the bitmap onto the canvas at the current bounds taking into account the current scale.
+     */
+    protected void drawBitmap(final Bitmap bitmap, final int width, final int height,
+            final Canvas canvas) {
+        final Rect bounds = getBounds();
+        // Draw bitmap through shader first.
+        final BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP,
+                Shader.TileMode.CLAMP);
+        mMatrix.reset();
+
+        // Fit bitmap to bounds.
+        final float boundsWidth = (float) bounds.width();
+        final float boundsHeight = (float) bounds.height();
+        final float scale = Math.max(boundsWidth / width, boundsHeight / height);
+        mMatrix.postScale(scale, scale);
+
+        // Translate bitmap to dst bounds.
+        mMatrix.postTranslate(bounds.left, bounds.top);
+
+        shader.setLocalMatrix(mMatrix);
+        mBitmapPaint.setShader(shader);
+        drawCircle(canvas, bounds, mBitmapPaint);
+
+        // Then draw the border.
+        final float radius = bounds.width() / 2f - mBorderWidth / 2;
+        canvas.drawCircle(bounds.centerX(), bounds.centerY(), radius, mBorderPaint);
+    }
+
+    /**
+     * Draws the largest circle that fits within the given <code>bounds</code>.
+     *
+     * @param canvas the canvas on which to draw
+     * @param bounds the bounding box of the circle
+     * @param paint the paint with which to draw
+     */
+    protected static void drawCircle(Canvas canvas, Rect bounds, Paint paint) {
+        canvas.drawCircle(bounds.centerX(), bounds.centerY(), bounds.width() / 2, paint);
+    }
+
+    @Override
+    public int getDecodeWidth() {
+        return mDecodedWidth;
+    }
+
+    @Override
+    public int getDecodeHeight() {
+        return mDecodedHeight;
+    }
+
+    public void setDecodeDimensions(final int decodeWidth, final int decodeHeight) {
+        mDecodedWidth = decodeWidth;
+        mDecodedHeight = decodeHeight;
+    }
+
+    public void unbind() {
+        setImage(null);
+    }
+
+    public void bind(final String name, final String email) {
+        setImage(new ContactRequest(name, email));
+    }
+
+    private void setImage(final ContactRequest contactRequest) {
+        if (mContactRequest != null && mContactRequest.equals(contactRequest)) {
+            return;
+        }
+
+        if (mBitmap != null) {
+            mBitmap.releaseReference();
+            mBitmap = null;
+        }
+
+        if (mContactResolver != null) {
+            mContactResolver.remove(mContactRequest, this);
+        }
+
+        mContactRequest = contactRequest;
+
+        if (contactRequest == null) {
+            invalidateSelf();
+            return;
+        }
+
+        ReusableBitmap cached = null;
+        if (mCache != null) {
+            cached = mCache.get(contactRequest, true /* incrementRefCount */);
+        }
+
+        if (cached != null) {
+            setBitmap(cached);
+        } else {
+            decode();
+        }
+    }
+
+    private void decode() {
+        if (mContactRequest == null) {
+            return;
+        }
+        // Add to batch.
+        mContactResolver.add(mContactRequest, this);
+    }
+
+    private void setBitmap(final ReusableBitmap bmp) {
+        if (mBitmap != null && mBitmap != bmp) {
+            mBitmap.releaseReference();
+        }
+        mBitmap = bmp;
+        invalidateSelf();
+    }
+
+    @Override
+    public void onDecodeComplete(RequestKey key, ReusableBitmap result) {
+        final ContactRequest request = (ContactRequest) key;
+        // Remove from batch.
+        mContactResolver.remove(request, this);
+        if (request.equals(mContactRequest)) {
+            setBitmap(result);
+        } else {
+            // if the requests don't match (i.e. this request is stale), decrement the
+            // ref count to allow the bitmap to be pooled
+            if (result != null) {
+                result.releaseReference();
+            }
+        }
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        mBitmapPaint.setAlpha(alpha);
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter cf) {
+        mBitmapPaint.setColorFilter(cf);
+    }
+
+    @Override
+    public int getOpacity() {
+        return 0;
+    }
+}
diff --git a/src/com/android/mail/bitmap/AccountAvatarDrawable.java b/src/com/android/mail/bitmap/AccountAvatarDrawable.java
index 21f14c1..3269440 100644
--- a/src/com/android/mail/bitmap/AccountAvatarDrawable.java
+++ b/src/com/android/mail/bitmap/AccountAvatarDrawable.java
@@ -18,58 +18,22 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.graphics.BitmapShader;
 import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Paint.Style;
-import android.graphics.Rect;
-import android.graphics.Shader.TileMode;
-import android.graphics.drawable.Drawable;
 
 import com.android.bitmap.BitmapCache;
-import com.android.bitmap.RequestKey;
-import com.android.bitmap.ReusableBitmap;
 import com.android.mail.R;
-import com.android.mail.bitmap.ContactResolver.ContactDrawableInterface;
 
-public class AccountAvatarDrawable extends Drawable implements ContactDrawableInterface {
-
-    private final BitmapCache mCache;
-    private final ContactResolver mContactResolver;
-
-    private ContactRequest mContactRequest;
-    private ReusableBitmap mBitmap;
-    private final float mBorderWidth;
-    private final Paint mBitmapPaint;
-    private final Paint mBorderPaint;
-    private final Matrix mMatrix;
-
-    private int mDecodeWidth;
-    private int mDecodeHeight;
-
+/**
+ * A contact drawable with a set default avatar.
+ */
+public class AccountAvatarDrawable extends AbstractAvatarDrawable {
     private static Bitmap DEFAULT_AVATAR = null;
 
     public AccountAvatarDrawable(final Resources res, final BitmapCache cache,
             final ContactResolver contactResolver) {
-        mCache = cache;
-        mContactResolver = contactResolver;
-        mBitmapPaint = new Paint();
-        mBitmapPaint.setAntiAlias(true);
-        mBitmapPaint.setFilterBitmap(true);
-        mBitmapPaint.setDither(true);
-
-        mBorderWidth = res.getDimensionPixelSize(R.dimen.avatar_border_width);
-
-        mBorderPaint = new Paint();
-        mBorderPaint.setColor(Color.TRANSPARENT);
-        mBorderPaint.setStyle(Style.STROKE);
-        mBorderPaint.setStrokeWidth(mBorderWidth);
-        mBorderPaint.setAntiAlias(true);
-
-        mMatrix = new Matrix();
+        super(res);
+        setBitmapCache(cache);
+        setContactResolver(contactResolver);
 
         if (DEFAULT_AVATAR == null) {
             DEFAULT_AVATAR = BitmapFactory.decodeResource(res, R.drawable.avatar_placeholder_gray);
@@ -77,144 +41,9 @@
     }
 
     @Override
-    public void draw(final Canvas canvas) {
-        final Rect bounds = getBounds();
-        if (!isVisible() || bounds.isEmpty()) {
-            return;
-        }
-
-        if (mBitmap != null && mBitmap.bmp != null) {
-            // Draw sender image.
-            drawBitmap(mBitmap.bmp, mBitmap.getLogicalWidth(), mBitmap.getLogicalHeight(), canvas);
-        } else {
-            // Draw the default image
-            drawBitmap(DEFAULT_AVATAR, DEFAULT_AVATAR.getWidth(), DEFAULT_AVATAR.getHeight(),
-                    canvas);
-        }
-    }
-
-    /**
-     * Draw the bitmap onto the canvas at the current bounds taking into account the current scale.
-     */
-    private void drawBitmap(final Bitmap bitmap, final int width, final int height,
-            final Canvas canvas) {
-        final Rect bounds = getBounds();
-        // Draw bitmap through shader first.
-        final BitmapShader shader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP);
-        mMatrix.reset();
-
-        // Fit bitmap to bounds.
-        final float boundsWidth = (float) bounds.width();
-        final float boundsHeight = (float) bounds.height();
-        final float scale = Math.max(boundsWidth / width, boundsHeight / height);
-        mMatrix.postScale(scale, scale);
-
-        // Translate bitmap to dst bounds.
-        mMatrix.postTranslate(bounds.left, bounds.top);
-
-        shader.setLocalMatrix(mMatrix);
-        mBitmapPaint.setShader(shader);
-        canvas.drawCircle(bounds.centerX(), bounds.centerY(), bounds.width() / 2, mBitmapPaint);
-
-        // Then draw the border.
-        final float radius = bounds.width() / 2f - mBorderWidth / 2;
-        canvas.drawCircle(bounds.centerX(), bounds.centerY(), radius, mBorderPaint);
-    }
-
-    @Override
-    public void setAlpha(final int alpha) {
-        mBitmapPaint.setAlpha(alpha);
-    }
-
-    @Override
-    public void setColorFilter(final ColorFilter cf) {
-        mBitmapPaint.setColorFilter(cf);
-    }
-
-    @Override
-    public int getOpacity() {
-        return 0;
-    }
-
-    public void setDecodeDimensions(final int decodeWidth, final int decodeHeight) {
-        mDecodeWidth = decodeWidth;
-        mDecodeHeight = decodeHeight;
-    }
-
-    public void unbind() {
-        setImage(null);
-    }
-
-    public void bind(final String name, final String email) {
-        setImage(new ContactRequest(name, email));
-    }
-
-    private void setImage(final ContactRequest contactRequest) {
-        if (mContactRequest != null && mContactRequest.equals(contactRequest)) {
-            return;
-        }
-
-        if (mBitmap != null) {
-            mBitmap.releaseReference();
-            mBitmap = null;
-        }
-
-        mContactResolver.remove(mContactRequest, this);
-        mContactRequest = contactRequest;
-
-        if (contactRequest == null) {
-            invalidateSelf();
-            return;
-        }
-
-        final ReusableBitmap cached = mCache.get(contactRequest, true /* incrementRefCount */);
-        if (cached != null) {
-            setBitmap(cached);
-        } else {
-            decode();
-        }
-    }
-
-    private void setBitmap(final ReusableBitmap bmp) {
-        if (mBitmap != null && mBitmap != bmp) {
-            mBitmap.releaseReference();
-        }
-        mBitmap = bmp;
-        invalidateSelf();
-    }
-
-    private void decode() {
-        if (mContactRequest == null) {
-            return;
-        }
-        // Add to batch.
-        mContactResolver.add(mContactRequest, this);
-    }
-
-    @Override
-    public int getDecodeWidth() {
-        return mDecodeWidth;
-    }
-
-    @Override
-    public int getDecodeHeight() {
-        return mDecodeHeight;
-    }
-
-    @Override
-    public void onDecodeComplete(final RequestKey key, final ReusableBitmap result) {
-        final ContactRequest request = (ContactRequest) key;
-        // Remove from batch.
-        mContactResolver.remove(request, this);
-        if (request.equals(mContactRequest)) {
-            setBitmap(result);
-        } else {
-            // if the requests don't match (i.e. this request is stale), decrement the
-            // ref count to allow the bitmap to be pooled
-            if (result != null) {
-                result.releaseReference();
-            }
-        }
+    protected void drawDefaultAvatar(Canvas canvas) {
+        drawBitmap(DEFAULT_AVATAR, DEFAULT_AVATAR.getWidth(), DEFAULT_AVATAR.getHeight(),
+                canvas);
     }
 }
 
diff --git a/src/com/android/mail/bitmap/ContactDrawable.java b/src/com/android/mail/bitmap/ContactDrawable.java
index a9b243c..badcc12 100644
--- a/src/com/android/mail/bitmap/ContactDrawable.java
+++ b/src/com/android/mail/bitmap/ContactDrawable.java
@@ -18,43 +18,18 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.graphics.BitmapShader;
 import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Paint.Align;
 import android.graphics.Rect;
-import android.graphics.Shader;
 import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
 
-import com.android.bitmap.BitmapCache;
-import com.android.bitmap.RequestKey;
-import com.android.bitmap.ReusableBitmap;
 import com.android.mail.R;
-import com.android.mail.bitmap.ContactResolver.ContactDrawableInterface;
 
 /**
- * A drawable that encapsulates all the functionality needed to display a contact image,
- * including request creation/cancelling and data unbinding/re-binding. While no contact images
- * can be shown, a default letter tile will be shown instead.
- * <p>
- * The actual contact resolving and decoding is handled by {@link ContactResolver}.
- * <p>
- * For better performance, you should define a cache with {@link #setBitmapCache(BitmapCache)}.
+ * A contact drawable with the default avatar as a letter tile.
  */
-public class ContactDrawable extends Drawable implements ContactDrawableInterface {
-
-    private final Resources mResources;
-    private BitmapCache mCache;
-    private ContactResolver mContactResolver;
-
-    private ContactRequest mContactRequest;
-    private ReusableBitmap mBitmap;
-    private final Paint mPaint;
-
+public class ContactDrawable extends AbstractAvatarDrawable {
     /** Letter tile */
     private static ColorPicker sTileColorPicker;
     private static int sTileLetterFontSize;
@@ -65,35 +40,8 @@
     private static final Rect sRect = new Rect();
     private static final char[] sFirstChar = new char[1];
 
-    private final float mBorderWidth;
-    private final Paint mBitmapPaint;
-    private final Paint mBorderPaint;
-    private final Matrix mMatrix;
-
-    private int mDecodeWidth;
-    private int mDecodeHeight;
-
     public ContactDrawable(final Resources res) {
-        mResources = res;
-
-        mPaint = new Paint();
-        mPaint.setFilterBitmap(true);
-        mPaint.setDither(true);
-
-        mBitmapPaint = new Paint();
-        mBitmapPaint.setAntiAlias(true);
-        mBitmapPaint.setFilterBitmap(true);
-        mBitmapPaint.setDither(true);
-
-        mBorderWidth = res.getDimensionPixelSize(R.dimen.avatar_border_width);
-
-        mBorderPaint = new Paint();
-        mBorderPaint.setColor(Color.TRANSPARENT);
-        mBorderPaint.setStyle(Paint.Style.STROKE);
-        mBorderPaint.setStrokeWidth(mBorderWidth);
-        mBorderPaint.setAntiAlias(true);
-
-        mMatrix = new Matrix();
+        super(res);
 
         if (sTileLetterFontSize == 0) {
             sTileLetterFontSize = res.getDimensionPixelSize(R.dimen.tile_letter_font_size_small);
@@ -106,14 +54,6 @@
         }
     }
 
-    public void setBitmapCache(final BitmapCache cache) {
-        mCache = cache;
-    }
-
-    public void setContactResolver(final ContactResolver contactResolver) {
-        mContactResolver = contactResolver;
-    }
-
     /**
      * Sets the {@link ColorPicker} for the background tile used in letter avatars.
      * @param colorPicker
@@ -135,48 +75,9 @@
     }
 
     @Override
-    public void draw(final Canvas canvas) {
-        final Rect bounds = getBounds();
-        if (!isVisible() || bounds.isEmpty()) {
-            return;
-        }
-
-        if (mBitmap != null && mBitmap.bmp != null) {
-            // Draw sender image.
-            drawBitmap(mBitmap.bmp, mBitmap.getLogicalWidth(), mBitmap.getLogicalHeight(), canvas);
-        } else {
-            // Draw letter tile.
-            drawLetterTile(canvas);
-        }
-    }
-
-    /**
-     * Draw the bitmap onto the canvas at the current bounds taking into account the current scale.
-     */
-    private void drawBitmap(final Bitmap bitmap, final int width, final int height,
-            final Canvas canvas) {
-        final Rect bounds = getBounds();
-        // Draw bitmap through shader first.
-        final BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP,
-                Shader.TileMode.CLAMP);
-        mMatrix.reset();
-
-        // Fit bitmap to bounds.
-        final float boundsWidth = (float) bounds.width();
-        final float boundsHeight = (float) bounds.height();
-        final float scale = Math.max(boundsWidth / width, boundsHeight / height);
-        mMatrix.postScale(scale, scale);
-
-        // Translate bitmap to dst bounds.
-        mMatrix.postTranslate(bounds.left, bounds.top);
-
-        shader.setLocalMatrix(mMatrix);
-        mBitmapPaint.setShader(shader);
-        drawCircle(canvas, bounds, mBitmapPaint);
-
-        // Then draw the border.
-        final float radius = bounds.width() / 2f - mBorderWidth / 2;
-        canvas.drawCircle(bounds.centerX(), bounds.centerY(), radius, mBorderPaint);
+    protected void drawDefaultAvatar(Canvas canvas) {
+        // Draw letter tile as default
+        drawLetterTile(canvas);
     }
 
     private void drawLetterTile(final Canvas canvas) {
@@ -190,7 +91,7 @@
         final String email = mContactRequest.getEmail();
         // The email should already have been normalized by the ContactRequest.
         sPaint.setColor(getTileColorPicker().pickColor(email));
-        sPaint.setAlpha(mPaint.getAlpha());
+        sPaint.setAlpha(mBitmapPaint.getAlpha());
         drawCircle(canvas, bounds, sPaint);
 
         // Draw letter/digit or generic avatar.
@@ -210,121 +111,7 @@
         }
     }
 
-    /**
-     * Draws the largest circle that fits within the given <code>bounds</code>.
-     *
-     * @param canvas the canvas on which to draw
-     * @param bounds the bounding box of the circle
-     * @param paint the paint with which to draw
-     */
-    private static void drawCircle(Canvas canvas, Rect bounds, Paint paint) {
-        canvas.drawCircle(bounds.centerX(), bounds.centerY(), bounds.width() / 2, paint);
-    }
-
     private static boolean isEnglishLetterOrDigit(final char c) {
         return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('0' <= c && c <= '9');
     }
-
-    @Override
-    public void setAlpha(final int alpha) {
-        mPaint.setAlpha(alpha);
-    }
-
-    @Override
-    public void setColorFilter(final ColorFilter cf) {
-        mPaint.setColorFilter(cf);
-    }
-
-    @Override
-    public int getOpacity() {
-        return 0;
-    }
-
-    public void setDecodeDimensions(final int decodeWidth, final int decodeHeight) {
-        mDecodeWidth = decodeWidth;
-        mDecodeHeight = decodeHeight;
-    }
-
-    public void unbind() {
-        setImage(null);
-    }
-
-    public void bind(final String name, final String email) {
-        setImage(new ContactRequest(name, email));
-    }
-
-    private void setImage(final ContactRequest contactRequest) {
-        if (mContactRequest != null && mContactRequest.equals(contactRequest)) {
-            return;
-        }
-
-        if (mBitmap != null) {
-            mBitmap.releaseReference();
-            mBitmap = null;
-        }
-
-        if (mContactResolver != null) {
-            mContactResolver.remove(mContactRequest, this);
-        }
-
-        mContactRequest = contactRequest;
-
-        if (contactRequest == null) {
-            invalidateSelf();
-            return;
-        }
-
-        ReusableBitmap cached = null;
-        if (mCache != null) {
-            cached = mCache.get(contactRequest, true /* incrementRefCount */);
-        }
-
-        if (cached != null) {
-            setBitmap(cached);
-        } else {
-            decode();
-        }
-    }
-
-    private void setBitmap(final ReusableBitmap bmp) {
-        if (mBitmap != null && mBitmap != bmp) {
-            mBitmap.releaseReference();
-        }
-        mBitmap = bmp;
-        invalidateSelf();
-    }
-
-    private void decode() {
-        if (mContactRequest == null) {
-            return;
-        }
-        // Add to batch.
-        mContactResolver.add(mContactRequest, this);
-    }
-
-    @Override
-    public int getDecodeWidth() {
-        return mDecodeWidth;
-    }
-
-    @Override
-    public int getDecodeHeight() {
-        return mDecodeHeight;
-    }
-
-    @Override
-    public void onDecodeComplete(final RequestKey key, final ReusableBitmap result) {
-        final ContactRequest request = (ContactRequest) key;
-        // Remove from batch.
-        mContactResolver.remove(request, this);
-        if (request.equals(mContactRequest)) {
-            setBitmap(result);
-        } else {
-            // if the requests don't match (i.e. this request is stale), decrement the
-            // ref count to allow the bitmap to be pooled
-            if (result != null) {
-                result.releaseReference();
-            }
-        }
-    }
 }
diff --git a/src/com/android/mail/bitmap/ContactResolver.java b/src/com/android/mail/bitmap/ContactResolver.java
index 5053c8e..7bb5d65 100644
--- a/src/com/android/mail/bitmap/ContactResolver.java
+++ b/src/com/android/mail/bitmap/ContactResolver.java
@@ -50,6 +50,10 @@
 
     private static final String TAG = LogTag.getLogTag();
 
+    // The maximum size returned from ContactsContract.Contacts.Photo.PHOTO is 96px by 96px.
+    private static final int MAXIMUM_PHOTO_SIZE = 96;
+    private static final int HALF_MAXIMUM_PHOTO_SIZE = 48;
+
     protected final ContentResolver mResolver;
     private final BitmapCache mCache;
     /** Insertion ordered set allows us to work from the top down. */
@@ -219,10 +223,12 @@
                 // Synchronously decode the photo bytes. We are already in a background
                 // thread, and we want decodes to finish in order. The decodes are blazing
                 // fast so we don't need to kick off multiple threads.
+                final int width = HALF_MAXIMUM_PHOTO_SIZE >= request.destination.getDecodeWidth()
+                        ? HALF_MAXIMUM_PHOTO_SIZE : MAXIMUM_PHOTO_SIZE;
+                final int height = HALF_MAXIMUM_PHOTO_SIZE >= request.destination.getDecodeHeight()
+                        ? HALF_MAXIMUM_PHOTO_SIZE : MAXIMUM_PHOTO_SIZE;
                 final DecodeTask.DecodeOptions opts = new DecodeTask.DecodeOptions(
-                        request.destination.getDecodeWidth(),
-                        request.destination.getDecodeHeight(), 1 / 2f,
-                        DecodeTask.DecodeOptions.STRATEGY_ROUND_NEAREST);
+                        width, height, 1 / 2f, DecodeTask.DecodeOptions.STRATEGY_ROUND_NEAREST);
                 final ReusableBitmap result = new DecodeTask(request.contactRequest, opts, null,
                         null, mCache).decode();
                 request.contactRequest.bytes = null;
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index 4451912..b00e83d 100644
--- a/src/com/android/mail/browse/ConversationItemView.java
+++ b/src/com/android/mail/browse/ConversationItemView.java
@@ -210,7 +210,7 @@
     private int mBackgroundOverrideResId = -1;
     /** The bitmap to use, or <code>null</code> for the default */
     private Bitmap mPhotoBitmap = null;
-    private Rect mPhotoRect = null;
+    private Rect mPhotoRect = new Rect();
 
     /**
      * A listener for clicks on the various areas of a conversation item.
@@ -672,8 +672,7 @@
                 mAdapter.getCoordinatesCache());
 
         if (mPhotoBitmap != null) {
-            mPhotoRect = new Rect(0, 0, mCoordinates.contactImagesWidth,
-                    mCoordinates.contactImagesHeight);
+            mPhotoRect.set(0, 0, mCoordinates.contactImagesWidth, mCoordinates.contactImagesHeight);
         }
 
         final int h = (mAnimatedHeightFraction != 1.0f) ?
diff --git a/src/com/android/mail/browse/MessageHeaderView.java b/src/com/android/mail/browse/MessageHeaderView.java
index 6570cd2..6770c3a 100644
--- a/src/com/android/mail/browse/MessageHeaderView.java
+++ b/src/com/android/mail/browse/MessageHeaderView.java
@@ -848,7 +848,6 @@
         boolean photoSet = false;
         final String email = mSender.getAddress();
         final ContactInfo info = mContactInfoSource.getContactInfo(email);
-        final Resources res = getResources();
         if (info != null) {
             if (info.contactUri != null) {
                 mPhotoView.assignContactUri(info.contactUri);