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