1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.mail.photomanager;
18
19import android.content.Context;
20import android.content.res.Resources;
21import android.content.res.TypedArray;
22import android.graphics.Bitmap;
23import android.graphics.BitmapFactory;
24import android.graphics.Canvas;
25import android.graphics.Paint.Align;
26import android.graphics.Rect;
27import android.graphics.Typeface;
28import android.text.TextPaint;
29import android.text.TextUtils;
30
31import com.android.mail.R;
32import com.android.mail.ui.ImageCanvas.Dimensions;
33import com.android.mail.utils.BitmapUtil;
34import com.android.mail.utils.LogTag;
35import com.android.mail.utils.LogUtils;
36
37/**
38 * LetterTileProvider is an implementation of the DefaultImageProvider. When no
39 * matching contact photo is found, and there is a supplied displayName or email
40 * address whose first letter corresponds to an English alphabet letter (or
41 * number), this method creates a bitmap with the letter in the center of a
42 * tile. If there is no English alphabet character (or digit), it creates a
43 * bitmap with the default contact avatar.
44 */
45@Deprecated
46public class LetterTileProvider {
47    private static final String TAG = LogTag.getLogTag();
48    private final Bitmap mDefaultBitmap;
49    private final Bitmap[] mBitmapBackgroundCache;
50    private final Bitmap[] mDefaultBitmapCache;
51    private final Typeface mSansSerifLight;
52    private final Rect mBounds;
53    private final int mTileLetterFontSize;
54    private final int mTileLetterFontSizeSmall;
55    private final int mTileFontColor;
56    private final TextPaint mPaint = new TextPaint();
57    private final TypedArray mColors;
58    private final int mColorCount;
59    private final int mDefaultColor;
60    private final Canvas mCanvas = new Canvas();
61    private final Dimensions mDims = new Dimensions();
62    private final char[] mFirstChar = new char[1];
63
64    private static final int POSSIBLE_BITMAP_SIZES = 3;
65
66    public LetterTileProvider(Context context) {
67        final Resources res = context.getResources();
68        mTileLetterFontSize = res.getDimensionPixelSize(R.dimen.tile_letter_font_size);
69        mTileLetterFontSizeSmall = res
70                .getDimensionPixelSize(R.dimen.tile_letter_font_size_small);
71        mTileFontColor = res.getColor(R.color.letter_tile_font_color);
72        mSansSerifLight = Typeface.create("sans-serif-light", Typeface.NORMAL);
73        mBounds = new Rect();
74        mPaint.setTypeface(mSansSerifLight);
75        mPaint.setColor(mTileFontColor);
76        mPaint.setTextAlign(Align.CENTER);
77        mPaint.setAntiAlias(true);
78        mBitmapBackgroundCache = new Bitmap[POSSIBLE_BITMAP_SIZES];
79
80        mDefaultBitmap = BitmapFactory.decodeResource(res, R.drawable.ic_generic_man);
81        mDefaultBitmapCache = new Bitmap[POSSIBLE_BITMAP_SIZES];
82
83        mColors = res.obtainTypedArray(R.array.letter_tile_colors);
84        mColorCount = mColors.length();
85        mDefaultColor = res.getColor(R.color.letter_tile_default_color);
86    }
87
88    public Bitmap getLetterTile(final Dimensions dimensions, final String displayName,
89            final String address) {
90        final String display = !TextUtils.isEmpty(displayName) ? displayName : address;
91        final char firstChar = display.charAt(0);
92
93        // get an empty bitmap
94        final Bitmap bitmap = getBitmap(dimensions, false /* getDefault */);
95        if (bitmap == null) {
96            LogUtils.w(TAG, "LetterTileProvider width(%d) or height(%d) is 0 for name %s and "
97                    + "address %s.", dimensions.width, dimensions.height, displayName, address);
98            return null;
99        }
100
101        final Canvas c = mCanvas;
102        c.setBitmap(bitmap);
103        c.drawColor(pickColor(address));
104
105        // If its a valid English alphabet letter,
106        // draw the letter on top of the color
107        if (isEnglishLetterOrDigit(firstChar)) {
108            mFirstChar[0] = Character.toUpperCase(firstChar);
109            mPaint.setTextSize(getFontSize(dimensions.scale));
110            mPaint.getTextBounds(mFirstChar, 0, 1, mBounds);
111            c.drawText(mFirstChar, 0, 1, 0 + dimensions.width / 2,
112                    0 + dimensions.height / 2 + (mBounds.bottom - mBounds.top) / 2, mPaint);
113        } else { // draw the generic icon on top
114            c.drawBitmap(getBitmap(dimensions, true /* getDefault */), 0, 0, null);
115        }
116
117        return bitmap;
118    }
119
120    private static boolean isEnglishLetterOrDigit(char c) {
121        return ('A' <= c && c <= 'Z')
122                || ('a' <= c && c <= 'z')
123                || ('0' <= c && c <= '9');
124    }
125
126    private Bitmap getBitmap(final Dimensions d, boolean getDefault) {
127        if (d.width <= 0 || d.height <= 0) {
128            LogUtils.w(TAG,
129                    "LetterTileProvider width(%d) or height(%d) is 0.", d.width, d.height);
130            return null;
131        }
132        final int pos;
133        float scale = d.scale;
134        if (scale == Dimensions.SCALE_ONE) {
135            pos = 0;
136        } else if (scale == Dimensions.SCALE_HALF) {
137            pos = 1;
138        } else {
139            pos = 2;
140        }
141
142        final Bitmap[] cache = (getDefault) ? mDefaultBitmapCache : mBitmapBackgroundCache;
143
144        Bitmap bitmap = cache[pos];
145        // ensure bitmap is suitable for the desired w/h
146        // (two-pane uses two different sets of dimensions depending on pane width)
147        if (bitmap == null || bitmap.getWidth() != d.width || bitmap.getHeight() != d.height) {
148            // create and place the bitmap
149            if (getDefault) {
150                bitmap = BitmapUtil.centerCrop(mDefaultBitmap, d.width, d.height);
151            } else {
152                bitmap = Bitmap.createBitmap(d.width, d.height, Bitmap.Config.ARGB_8888);
153            }
154            cache[pos] = bitmap;
155        }
156        return bitmap;
157    }
158
159    private int getFontSize(float scale)  {
160        if (scale == Dimensions.SCALE_ONE) {
161            return mTileLetterFontSize;
162        } else {
163            return mTileLetterFontSizeSmall;
164        }
165    }
166
167    private int pickColor(String emailAddress) {
168        // String.hashCode() implementation is not supposed to change across java versions, so
169        // this should guarantee the same email address always maps to the same color.
170        int color = Math.abs(emailAddress.hashCode()) % mColorCount;
171        return mColors.getColor(color, mDefaultColor);
172    }
173}
174