Refactoring in ContactDrawable to pick a color.

Strategy pattern to pick a color in the letter tile.

Thanks to this, subimplementations can draw the letter tiles
for avatars differently, and still use the all the features
of the ContactDrawable.

Bug: 16378212 Draw letter tile for non-Gmail avatars
Change-Id: I999aa43724ba0e4dd23f2106133aaa34ee3ba008
diff --git a/src/com/android/mail/bitmap/ColorPicker.java b/src/com/android/mail/bitmap/ColorPicker.java
new file mode 100644
index 0000000..f8303d9
--- /dev/null
+++ b/src/com/android/mail/bitmap/ColorPicker.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ * Licensed to 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.content.res.TypedArray;
+
+import com.android.mail.R;
+
+public interface ColorPicker {
+    /**
+     * Returns the color to use for the given email address.
+     * This method should return the same output for the same input.
+     * @param email The normalized email address.
+     * @return The color value in the format {@code 0xAARRGGBB}.
+     */
+    public int pickColor(final String email);
+
+    /**
+     * A simple implementation of a {@link ColorPicker}.
+     */
+    public class PaletteColorPicker implements ColorPicker {
+        /**
+         * The palette of colors, inflated from {@code R.array.letter_tile_colors}.
+         */
+        private static TypedArray sColors;
+
+        /**
+         * Cached value of {@code sColors.length()}.
+         */
+        private static int sColorCount;
+
+        /**
+         * Default color returned if the one chosen from {@code R.array.letter_tile_colors} is
+         * a {@link android.content.res.ColorStateList}.
+         */
+        private static int sDefaultColor;
+
+        public PaletteColorPicker(Resources res) {
+            if (sColors == null) {
+                sColors = res.obtainTypedArray(R.array.letter_tile_colors);
+                sColorCount = sColors.length();
+                sDefaultColor = res.getColor(R.color.letter_tile_default_color);
+            }
+        }
+
+        @Override
+        public int pickColor(final String email) {
+            final int color = Math.abs(email.hashCode()) % sColorCount;
+            return sColors.getColor(color, sDefaultColor);
+        }
+    }
+}
diff --git a/src/com/android/mail/bitmap/ContactDrawable.java b/src/com/android/mail/bitmap/ContactDrawable.java
index 7b10690..34983bf 100644
--- a/src/com/android/mail/bitmap/ContactDrawable.java
+++ b/src/com/android/mail/bitmap/ContactDrawable.java
@@ -16,7 +16,6 @@
 package com.android.mail.bitmap;
 
 import android.content.res.Resources;
-import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.BitmapShader;
@@ -48,6 +47,7 @@
  */
 public class ContactDrawable extends Drawable implements ContactDrawableInterface {
 
+    private final Resources mResources;
     private BitmapCache mCache;
     private ContactResolver mContactResolver;
 
@@ -56,9 +56,7 @@
     private final Paint mPaint;
 
     /** Letter tile */
-    private static TypedArray sColors;
-    private static int sColorCount;
-    private static int sDefaultColor;
+    private static ColorPicker sTileColorPicker;
     private static int sTileLetterFontSize;
     private static int sTileFontColor;
     private static Bitmap DEFAULT_AVATAR;
@@ -76,6 +74,8 @@
     private int mDecodeHeight;
 
     public ContactDrawable(final Resources res) {
+        mResources = res;
+
         mPaint = new Paint();
         mPaint.setFilterBitmap(true);
         mPaint.setDither(true);
@@ -95,10 +95,7 @@
 
         mMatrix = new Matrix();
 
-        if (sColors == null) {
-            sColors = res.obtainTypedArray(R.array.letter_tile_colors);
-            sColorCount = sColors.length();
-            sDefaultColor = res.getColor(R.color.letter_tile_default_color);
+        if (sTileLetterFontSize == 0) {
             sTileLetterFontSize = res.getDimensionPixelSize(R.dimen.tile_letter_font_size);
             sTileFontColor = res.getColor(R.color.letter_tile_font_color);
             DEFAULT_AVATAR = BitmapFactory.decodeResource(res, R.drawable.ic_generic_man);
@@ -117,6 +114,26 @@
         mContactResolver = contactResolver;
     }
 
+    /**
+     * Sets the {@link ColorPicker} for the background tile used in letter avatars.
+     * @param colorPicker
+     */
+    public static void setTileColorPicker(ColorPicker colorPicker) {
+        sTileColorPicker = colorPicker;
+    }
+
+    /**
+     * Returns the color picker for the background tile used in the letter avatars.
+     * If none was set, initializes a simple {@link ColorPicker.PaletteColorPicker} first.
+     * @return non-null color picker.
+     */
+    public ColorPicker getTileColorPicker() {
+        if (sTileColorPicker == null) {
+            sTileColorPicker = new ColorPicker.PaletteColorPicker(mResources);
+        }
+        return sTileColorPicker;
+    }
+
     @Override
     public void draw(final Canvas canvas) {
         final Rect bounds = getBounds();
@@ -171,7 +188,8 @@
 
         // Draw background color.
         final String email = mContactRequest.getEmail();
-        sPaint.setColor(pickColor(email));
+        // The email should already have been normalized by the ContactRequest.
+        sPaint.setColor(getTileColorPicker().pickColor(email));
         sPaint.setAlpha(mPaint.getAlpha());
         drawCircle(canvas, bounds, sPaint);
 
@@ -203,14 +221,6 @@
         canvas.drawCircle(bounds.centerX(), bounds.centerY(), bounds.width() / 2, paint);
     }
 
-    private static int pickColor(final String email) {
-        // String.hashCode() implementation is not supposed to change across java versions, so
-        // this should guarantee the same email address always maps to the same color.
-        // The email should already have been normalized by the ContactRequest.
-        final int color = Math.abs(email.hashCode()) % sColorCount;
-        return sColors.getColor(color, sDefaultColor);
-    }
-
     private static boolean isEnglishLetterOrDigit(final char c) {
         return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('0' <= c && c <= '9');
     }
diff --git a/src/com/android/mail/photomanager/LetterTileProvider.java b/src/com/android/mail/photomanager/LetterTileProvider.java
index bf17acb..ca70e72 100644
--- a/src/com/android/mail/photomanager/LetterTileProvider.java
+++ b/src/com/android/mail/photomanager/LetterTileProvider.java
@@ -29,6 +29,7 @@
 import android.text.TextUtils;
 
 import com.android.mail.R;
+import com.android.mail.bitmap.ColorPicker;
 import com.android.mail.ui.ImageCanvas.Dimensions;
 import com.android.mail.utils.BitmapUtil;
 import com.android.mail.utils.LogTag;
@@ -54,14 +55,11 @@
     private final int mTileLetterFontSizeSmall;
     private final int mTileFontColor;
     private final TextPaint mPaint = new TextPaint();
-    private final TypedArray mColors;
-    private final int mColorCount;
-    private final int mDefaultColor;
     private final Canvas mCanvas = new Canvas();
-    private final Dimensions mDims = new Dimensions();
     private final char[] mFirstChar = new char[1];
 
     private static final int POSSIBLE_BITMAP_SIZES = 3;
+    private ColorPicker sTileColorPicker;
 
     public LetterTileProvider(Context context) {
         final Resources res = context.getResources();
@@ -80,9 +78,9 @@
         mDefaultBitmap = BitmapFactory.decodeResource(res, R.drawable.ic_generic_man);
         mDefaultBitmapCache = new Bitmap[POSSIBLE_BITMAP_SIZES];
 
-        mColors = res.obtainTypedArray(R.array.letter_tile_colors);
-        mColorCount = mColors.length();
-        mDefaultColor = res.getColor(R.color.letter_tile_default_color);
+        if (sTileColorPicker == null) {
+            sTileColorPicker = new ColorPicker.PaletteColorPicker(res);
+        }
     }
 
     public Bitmap getLetterTile(final Dimensions dimensions, final String displayName,
@@ -100,7 +98,7 @@
 
         final Canvas c = mCanvas;
         c.setBitmap(bitmap);
-        c.drawColor(pickColor(address));
+        c.drawColor(sTileColorPicker.pickColor(address));
 
         // If its a valid English alphabet letter,
         // draw the letter on top of the color
@@ -163,11 +161,4 @@
             return mTileLetterFontSizeSmall;
         }
     }
-
-    private int pickColor(String emailAddress) {
-        // String.hashCode() implementation is not supposed to change across java versions, so
-        // this should guarantee the same email address always maps to the same color.
-        int color = Math.abs(emailAddress.hashCode()) % mColorCount;
-        return mColors.getColor(color, mDefaultColor);
-    }
 }