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