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