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 17 package com.android.mail.photomanager; 18 19 import android.content.res.Resources; 20 import android.graphics.Bitmap; 21 import android.graphics.BitmapFactory; 22 import android.graphics.Canvas; 23 import android.graphics.Paint.Align; 24 import android.graphics.Rect; 25 import android.graphics.Typeface; 26 import android.text.TextPaint; 27 import android.text.TextUtils; 28 29 import com.android.mail.R; 30 import com.android.mail.bitmap.ColorPicker; 31 import com.android.mail.ui.ImageCanvas.Dimensions; 32 import com.android.mail.utils.BitmapUtil; 33 import com.android.mail.utils.LogTag; 34 import com.android.mail.utils.LogUtils; 35 36 /** 37 * LetterTileProvider is an implementation of the DefaultImageProvider. When no 38 * matching contact photo is found, and there is a supplied displayName or email 39 * address whose first letter corresponds to an English alphabet letter (or 40 * number), this method creates a bitmap with the letter in the center of a 41 * tile. If there is no English alphabet character (or digit), it creates a 42 * bitmap with the default contact avatar. 43 */ 44 public class LetterTileProvider { 45 private static final String TAG = LogTag.getLogTag(); 46 private final Bitmap mDefaultBitmap; 47 private final Bitmap[] mBitmapBackgroundCache; 48 private final Bitmap[] mDefaultBitmapCache; 49 private final Typeface mSansSerifLight; 50 private final Rect mBounds; 51 private final int mTileLetterFontSize; 52 private final int mTileLetterFontSizeSmall; 53 private final int mTileFontColor; 54 private final TextPaint mPaint = new TextPaint(); 55 private final Canvas mCanvas = new Canvas(); 56 private final char[] mFirstChar = new char[1]; 57 58 private static final int POSSIBLE_BITMAP_SIZES = 3; 59 private final ColorPicker mTileColorPicker; 60 61 public LetterTileProvider(Resources res) { 62 this(res, new ColorPicker.PaletteColorPicker(res)); 63 } 64 65 public LetterTileProvider(Resources res, ColorPicker colorPicker) { 66 mTileLetterFontSize = res.getDimensionPixelSize(R.dimen.tile_letter_font_size_small); 67 mTileLetterFontSizeSmall = res.getDimensionPixelSize(R.dimen.tile_letter_font_size_tiny); 68 mTileFontColor = res.getColor(R.color.letter_tile_font_color); 69 mSansSerifLight = Typeface.create("sans-serif-light", Typeface.NORMAL); 70 mBounds = new Rect(); 71 mPaint.setTypeface(mSansSerifLight); 72 mPaint.setColor(mTileFontColor); 73 mPaint.setTextAlign(Align.CENTER); 74 mPaint.setAntiAlias(true); 75 mBitmapBackgroundCache = new Bitmap[POSSIBLE_BITMAP_SIZES]; 76 77 mDefaultBitmap = BitmapFactory.decodeResource(res, R.drawable.ic_anonymous_avatar_40dp); 78 mDefaultBitmapCache = new Bitmap[POSSIBLE_BITMAP_SIZES]; 79 80 mTileColorPicker = colorPicker; 81 } 82 83 public Bitmap getLetterTile(final Dimensions dimensions, final String displayName, 84 final String address) { 85 final String display = !TextUtils.isEmpty(displayName) ? displayName : address; 86 final char firstChar = display.charAt(0); 87 88 // get an empty bitmap 89 final Bitmap bitmap = getBitmap(dimensions, false /* getDefault */); 90 if (bitmap == null) { 91 LogUtils.w(TAG, "LetterTileProvider width(%d) or height(%d) is 0 for name %s and " 92 + "address %s.", dimensions.width, dimensions.height, displayName, address); 93 return null; 94 } 95 96 final Canvas c = mCanvas; 97 c.setBitmap(bitmap); 98 c.drawColor(mTileColorPicker.pickColor(address)); 99 100 // If its a valid English alphabet letter, 101 // draw the letter on top of the color 102 if (isEnglishLetterOrDigit(firstChar)) { 103 mFirstChar[0] = Character.toUpperCase(firstChar); 104 mPaint.setTextSize( 105 dimensions.fontSize > 0 ? dimensions.fontSize : getFontSize(dimensions.scale)); 106 mPaint.getTextBounds(mFirstChar, 0, 1, mBounds); 107 c.drawText(mFirstChar, 0, 1, 0 + dimensions.width / 2, 108 0 + dimensions.height / 2 + (mBounds.bottom - mBounds.top) / 2, mPaint); 109 } else { // draw the generic icon on top 110 c.drawBitmap(getBitmap(dimensions, true /* getDefault */), 0, 0, null); 111 } 112 113 return bitmap; 114 } 115 116 private static boolean isEnglishLetterOrDigit(char c) { 117 return ('A' <= c && c <= 'Z') 118 || ('a' <= c && c <= 'z') 119 || ('0' <= c && c <= '9'); 120 } 121 122 private Bitmap getBitmap(final Dimensions d, boolean getDefault) { 123 if (d.width <= 0 || d.height <= 0) { 124 LogUtils.w(TAG, 125 "LetterTileProvider width(%d) or height(%d) is 0.", d.width, d.height); 126 return null; 127 } 128 final int pos; 129 float scale = d.scale; 130 if (scale == Dimensions.SCALE_ONE) { 131 pos = 0; 132 } else if (scale == Dimensions.SCALE_HALF) { 133 pos = 1; 134 } else { 135 pos = 2; 136 } 137 138 final Bitmap[] cache = (getDefault) ? mDefaultBitmapCache : mBitmapBackgroundCache; 139 140 Bitmap bitmap = cache[pos]; 141 // ensure bitmap is suitable for the desired w/h 142 // (two-pane uses two different sets of dimensions depending on pane width) 143 if (bitmap == null || bitmap.getWidth() != d.width || bitmap.getHeight() != d.height) { 144 // create and place the bitmap 145 if (getDefault) { 146 bitmap = BitmapUtil.centerCrop(mDefaultBitmap, d.width, d.height); 147 } else { 148 bitmap = Bitmap.createBitmap(d.width, d.height, Bitmap.Config.ARGB_8888); 149 } 150 cache[pos] = bitmap; 151 } 152 return bitmap; 153 } 154 155 private int getFontSize(float scale) { 156 if (scale == Dimensions.SCALE_ONE) { 157 return mTileLetterFontSize; 158 } else { 159 return mTileLetterFontSizeSmall; 160 } 161 } 162 } 163