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