1 /* 2 * Copyright (C) 2012 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.gallery3d.ui; 18 19 import android.content.Context; 20 import android.graphics.Bitmap; 21 import android.graphics.Bitmap.Config; 22 import android.graphics.BitmapFactory; 23 import android.graphics.Canvas; 24 import android.graphics.Color; 25 import android.graphics.PorterDuff; 26 import android.graphics.Typeface; 27 import android.text.TextPaint; 28 import android.text.TextUtils; 29 30 import com.android.gallery3d.R; 31 import com.android.gallery3d.data.BitmapPool; 32 import com.android.gallery3d.data.DataSourceType; 33 import com.android.gallery3d.util.ThreadPool; 34 import com.android.gallery3d.util.ThreadPool.JobContext; 35 36 public class AlbumLabelMaker { 37 private static final int FONT_COLOR_TITLE = Color.WHITE; 38 private static final int FONT_COLOR_COUNT = 0x80FFFFFF; // 50% white 39 40 // We keep a border around the album label to prevent aliasing 41 private static final int BORDER_SIZE = 1; 42 private static final int BACKGROUND_COLOR = 0x60000000; // 36% Dark 43 44 private final AlbumSetSlotRenderer.LabelSpec mSpec; 45 private final TextPaint mTitlePaint; 46 private final TextPaint mCountPaint; 47 private final Context mContext; 48 49 private int mLabelWidth; 50 private BitmapPool mBitmapPool; 51 52 private final LazyLoadedBitmap mLocalSetIcon; 53 private final LazyLoadedBitmap mPicasaIcon; 54 private final LazyLoadedBitmap mCameraIcon; 55 private final LazyLoadedBitmap mMtpIcon; 56 AlbumLabelMaker(Context context, AlbumSetSlotRenderer.LabelSpec spec)57 public AlbumLabelMaker(Context context, AlbumSetSlotRenderer.LabelSpec spec) { 58 mContext = context; 59 mSpec = spec; 60 mTitlePaint = getTextPaint(spec.titleFontSize, FONT_COLOR_TITLE, false); 61 mCountPaint = getTextPaint(spec.countFontSize, FONT_COLOR_COUNT, true); 62 63 mLocalSetIcon = new LazyLoadedBitmap(R.drawable.frame_overlay_gallery_folder); 64 mPicasaIcon = new LazyLoadedBitmap(R.drawable.frame_overlay_gallery_picasa); 65 mCameraIcon = new LazyLoadedBitmap(R.drawable.frame_overlay_gallery_camera); 66 mMtpIcon = new LazyLoadedBitmap(R.drawable.frame_overlay_gallery_ptp); 67 } 68 getBorderSize()69 public static int getBorderSize() { 70 return BORDER_SIZE; 71 } 72 getOverlayAlbumIcon(int sourceType)73 private Bitmap getOverlayAlbumIcon(int sourceType) { 74 switch (sourceType) { 75 case DataSourceType.TYPE_CAMERA: 76 return mCameraIcon.get(); 77 case DataSourceType.TYPE_LOCAL: 78 return mLocalSetIcon.get(); 79 case DataSourceType.TYPE_MTP: 80 return mMtpIcon.get(); 81 case DataSourceType.TYPE_PICASA: 82 return mPicasaIcon.get(); 83 } 84 return null; 85 } 86 getTextPaint(int textSize, int color, boolean isBold)87 private static TextPaint getTextPaint(int textSize, int color, boolean isBold) { 88 TextPaint paint = new TextPaint(); 89 paint.setTextSize(textSize); 90 paint.setAntiAlias(true); 91 paint.setColor(color); 92 paint.setShadowLayer(2f, 0f, 0f, Color.BLACK); 93 if (isBold) { 94 paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); 95 } 96 return paint; 97 } 98 99 private class LazyLoadedBitmap { 100 private Bitmap mBitmap; 101 private int mResId; 102 LazyLoadedBitmap(int resId)103 public LazyLoadedBitmap(int resId) { 104 mResId = resId; 105 } 106 get()107 public synchronized Bitmap get() { 108 if (mBitmap == null) { 109 BitmapFactory.Options options = new BitmapFactory.Options(); 110 options.inPreferredConfig = Bitmap.Config.ARGB_8888; 111 mBitmap = BitmapFactory.decodeResource( 112 mContext.getResources(), mResId, options); 113 } 114 return mBitmap; 115 } 116 } 117 setLabelWidth(int width)118 public synchronized void setLabelWidth(int width) { 119 if (mLabelWidth == width) return; 120 mLabelWidth = width; 121 int borders = 2 * BORDER_SIZE; 122 mBitmapPool = new BitmapPool( 123 width + borders, mSpec.labelBackgroundHeight + borders, 16); 124 } 125 requestLabel( String title, String count, int sourceType)126 public ThreadPool.Job<Bitmap> requestLabel( 127 String title, String count, int sourceType) { 128 return new AlbumLabelJob(title, count, sourceType); 129 } 130 drawText(Canvas canvas, int x, int y, String text, int lengthLimit, TextPaint p)131 static void drawText(Canvas canvas, 132 int x, int y, String text, int lengthLimit, TextPaint p) { 133 // The TextPaint cannot be used concurrently 134 synchronized (p) { 135 text = TextUtils.ellipsize( 136 text, p, lengthLimit, TextUtils.TruncateAt.END).toString(); 137 canvas.drawText(text, x, y - p.getFontMetricsInt().ascent, p); 138 } 139 } 140 141 private class AlbumLabelJob implements ThreadPool.Job<Bitmap> { 142 private final String mTitle; 143 private final String mCount; 144 private final int mSourceType; 145 AlbumLabelJob(String title, String count, int sourceType)146 public AlbumLabelJob(String title, String count, int sourceType) { 147 mTitle = title; 148 mCount = count; 149 mSourceType = sourceType; 150 } 151 152 @Override run(JobContext jc)153 public Bitmap run(JobContext jc) { 154 AlbumSetSlotRenderer.LabelSpec s = mSpec; 155 156 String title = mTitle; 157 String count = mCount; 158 Bitmap icon = getOverlayAlbumIcon(mSourceType); 159 160 Bitmap bitmap; 161 int labelWidth; 162 163 synchronized (this) { 164 labelWidth = mLabelWidth; 165 bitmap = mBitmapPool.getBitmap(); 166 } 167 168 if (bitmap == null) { 169 int borders = 2 * BORDER_SIZE; 170 bitmap = Bitmap.createBitmap(labelWidth + borders, 171 s.labelBackgroundHeight + borders, Config.ARGB_8888); 172 } 173 174 Canvas canvas = new Canvas(bitmap); 175 canvas.clipRect(BORDER_SIZE, BORDER_SIZE, 176 bitmap.getWidth() - BORDER_SIZE, 177 bitmap.getHeight() - BORDER_SIZE); 178 canvas.drawColor(BACKGROUND_COLOR, PorterDuff.Mode.SRC); 179 180 canvas.translate(BORDER_SIZE, BORDER_SIZE); 181 182 // draw title 183 if (jc.isCancelled()) return null; 184 int x = s.leftMargin; 185 int y = s.titleOffset; 186 drawText(canvas, x, y, title, labelWidth - s.leftMargin, mTitlePaint); 187 188 // draw the count 189 if (jc.isCancelled()) return null; 190 if (icon != null) x = s.iconSize; 191 y += s.titleFontSize + s.countOffset; 192 drawText(canvas, x, y, count, 193 labelWidth - s.leftMargin - s.iconSize, mCountPaint); 194 195 // draw the icon 196 if (icon != null) { 197 if (jc.isCancelled()) return null; 198 float scale = (float) s.iconSize / icon.getWidth(); 199 canvas.translate(0, bitmap.getHeight() 200 - Math.round(scale * icon.getHeight())); 201 canvas.scale(scale, scale); 202 canvas.drawBitmap(icon, 0, 0, null); 203 } 204 205 return bitmap; 206 } 207 } 208 recycleLabel(Bitmap label)209 public void recycleLabel(Bitmap label) { 210 mBitmapPool.recycle(label); 211 } 212 clearRecycledLabels()213 public void clearRecycledLabels() { 214 if (mBitmapPool != null) mBitmapPool.clear(); 215 } 216 } 217