1b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang/*
2b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang * Copyright (C) 2012 The Android Open Source Project
3b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang *
4b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang * Licensed under the Apache License, Version 2.0 (the "License");
5b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang * you may not use this file except in compliance with the License.
6b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang * You may obtain a copy of the License at
7b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang *
8b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang *      http://www.apache.org/licenses/LICENSE-2.0
9b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang *
10b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang * Unless required by applicable law or agreed to in writing, software
11b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang * distributed under the License is distributed on an "AS IS" BASIS,
12b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang * See the License for the specific language governing permissions and
14b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang * limitations under the License.
15b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang */
161a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
171a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Linpackage com.android.gallery3d.ui;
181a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
191a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Linimport android.content.Context;
201a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Linimport android.graphics.Bitmap;
211a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Linimport android.graphics.Bitmap.Config;
221a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Linimport android.graphics.BitmapFactory;
231a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Linimport android.graphics.Canvas;
24d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Linimport android.graphics.PorterDuff;
251a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Linimport android.graphics.Typeface;
261a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Linimport android.text.TextPaint;
271a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Linimport android.text.TextUtils;
281a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
291a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Linimport com.android.gallery3d.R;
3031cac30e46a293f6d0901e22c6ab0d083cae7021Owen Linimport com.android.gallery3d.data.DataSourceType;
31f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescuimport com.android.photos.data.GalleryBitmapPool;
321a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Linimport com.android.gallery3d.util.ThreadPool;
331a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Linimport com.android.gallery3d.util.ThreadPool.JobContext;
341a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
351a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Linpublic class AlbumLabelMaker {
36c90a116a7fd65d41e8258dc7b9a14218649697e6Bobby Georgescu    private static final int BORDER_SIZE = 0;
37cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin
38c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin    private final AlbumSetSlotRenderer.LabelSpec mSpec;
391a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private final TextPaint mTitlePaint;
401a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private final TextPaint mCountPaint;
411a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private final Context mContext;
421a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
43d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    private int mLabelWidth;
44f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu    private int mBitmapWidth;
45f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu    private int mBitmapHeight;
46d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin
471a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private final LazyLoadedBitmap mLocalSetIcon;
481a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private final LazyLoadedBitmap mPicasaIcon;
491a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private final LazyLoadedBitmap mCameraIcon;
501a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
51c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin    public AlbumLabelMaker(Context context, AlbumSetSlotRenderer.LabelSpec spec) {
521a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        mContext = context;
531a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        mSpec = spec;
54915c2c5b2c367df71599370613af0924bd7c4887Bobby Georgescu        mTitlePaint = getTextPaint(spec.titleFontSize, spec.titleColor, false);
55915c2c5b2c367df71599370613af0924bd7c4887Bobby Georgescu        mCountPaint = getTextPaint(spec.countFontSize, spec.countColor, false);
561a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
571a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        mLocalSetIcon = new LazyLoadedBitmap(R.drawable.frame_overlay_gallery_folder);
581a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        mPicasaIcon = new LazyLoadedBitmap(R.drawable.frame_overlay_gallery_picasa);
591a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        mCameraIcon = new LazyLoadedBitmap(R.drawable.frame_overlay_gallery_camera);
601a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    }
611a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
62cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin    public static int getBorderSize() {
63cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        return BORDER_SIZE;
64cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin    }
65cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin
661a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private Bitmap getOverlayAlbumIcon(int sourceType) {
671a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        switch (sourceType) {
6831cac30e46a293f6d0901e22c6ab0d083cae7021Owen Lin            case DataSourceType.TYPE_CAMERA:
691a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                return mCameraIcon.get();
7031cac30e46a293f6d0901e22c6ab0d083cae7021Owen Lin            case DataSourceType.TYPE_LOCAL:
711a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                return mLocalSetIcon.get();
7231cac30e46a293f6d0901e22c6ab0d083cae7021Owen Lin            case DataSourceType.TYPE_PICASA:
731a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                return mPicasaIcon.get();
741a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        }
751a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        return null;
761a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    }
771a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
781a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private static TextPaint getTextPaint(int textSize, int color, boolean isBold) {
791a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        TextPaint paint = new TextPaint();
801a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        paint.setTextSize(textSize);
811a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        paint.setAntiAlias(true);
821a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        paint.setColor(color);
83c90a116a7fd65d41e8258dc7b9a14218649697e6Bobby Georgescu        //paint.setShadowLayer(2f, 0f, 0f, Color.LTGRAY);
841a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        if (isBold) {
851a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
861a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        }
871a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        return paint;
881a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    }
891a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
901a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private class LazyLoadedBitmap {
911a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        private Bitmap mBitmap;
921a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        private int mResId;
931a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
941a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public LazyLoadedBitmap(int resId) {
951a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            mResId = resId;
961a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        }
971a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
981a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public synchronized Bitmap get() {
991a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            if (mBitmap == null) {
1001a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                BitmapFactory.Options options = new BitmapFactory.Options();
1011a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                options.inPreferredConfig = Bitmap.Config.ARGB_8888;
1021a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                mBitmap = BitmapFactory.decodeResource(
1031a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                        mContext.getResources(), mResId, options);
1041a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            }
1051a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            return mBitmap;
1061a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        }
1071a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    }
1081a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
109d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    public synchronized void setLabelWidth(int width) {
110d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin        if (mLabelWidth == width) return;
111d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin        mLabelWidth = width;
112cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        int borders = 2 * BORDER_SIZE;
113f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu        mBitmapWidth = width + borders;
114f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu        mBitmapHeight = mSpec.labelBackgroundHeight + borders;
115d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    }
116d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin
1171a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    public ThreadPool.Job<Bitmap> requestLabel(
118d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            String title, String count, int sourceType) {
1198ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin        return new AlbumLabelJob(title, count, sourceType);
1201a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    }
1211a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
1228ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin    static void drawText(Canvas canvas,
1231a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            int x, int y, String text, int lengthLimit, TextPaint p) {
1241a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        // The TextPaint cannot be used concurrently
1251a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        synchronized (p) {
1261a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            text = TextUtils.ellipsize(
1271a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                    text, p, lengthLimit, TextUtils.TruncateAt.END).toString();
1281a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            canvas.drawText(text, x, y - p.getFontMetricsInt().ascent, p);
1291a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        }
1301a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    }
1311a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
1321a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private class AlbumLabelJob implements ThreadPool.Job<Bitmap> {
1331a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        private final String mTitle;
1341a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        private final String mCount;
1351a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        private final int mSourceType;
1361a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
1378ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin        public AlbumLabelJob(String title, String count, int sourceType) {
1381a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            mTitle = title;
1391a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            mCount = count;
1401a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            mSourceType = sourceType;
1411a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        }
1421a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
1431a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        @Override
1441a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public Bitmap run(JobContext jc) {
145c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin            AlbumSetSlotRenderer.LabelSpec s = mSpec;
1461a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
1478ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin            String title = mTitle;
1488ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin            String count = mCount;
1491a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            Bitmap icon = getOverlayAlbumIcon(mSourceType);
150d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin
151cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin            Bitmap bitmap;
152d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            int labelWidth;
153d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin
154d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            synchronized (this) {
155d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin                labelWidth = mLabelWidth;
156f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu                bitmap = GalleryBitmapPool.getInstance().get(mBitmapWidth, mBitmapHeight);
157d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            }
158cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin
159d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            if (bitmap == null) {
160cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin                int borders = 2 * BORDER_SIZE;
161cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin                bitmap = Bitmap.createBitmap(labelWidth + borders,
162cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin                        s.labelBackgroundHeight + borders, Config.ARGB_8888);
163d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            }
1641a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
165cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin            Canvas canvas = new Canvas(bitmap);
166cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin            canvas.clipRect(BORDER_SIZE, BORDER_SIZE,
167cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin                    bitmap.getWidth() - BORDER_SIZE,
168cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin                    bitmap.getHeight() - BORDER_SIZE);
169915c2c5b2c367df71599370613af0924bd7c4887Bobby Georgescu            canvas.drawColor(mSpec.backgroundColor, PorterDuff.Mode.SRC);
170cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin
171cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin            canvas.translate(BORDER_SIZE, BORDER_SIZE);
172cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin
1731a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            // draw title
1741a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            if (jc.isCancelled()) return null;
175c90a116a7fd65d41e8258dc7b9a14218649697e6Bobby Georgescu            int x = s.leftMargin + s.iconSize;
176e24cc7208a6d3760a87dfd4b80a7a6683fe146ebBobby Georgescu            // TODO: is the offset relevant in new reskin?
177e24cc7208a6d3760a87dfd4b80a7a6683fe146ebBobby Georgescu            // int y = s.titleOffset;
178e24cc7208a6d3760a87dfd4b80a7a6683fe146ebBobby Georgescu            int y = (s.labelBackgroundHeight - s.titleFontSize) / 2;
179e24cc7208a6d3760a87dfd4b80a7a6683fe146ebBobby Georgescu            drawText(canvas, x, y, title, labelWidth - s.leftMargin - x -
180e24cc7208a6d3760a87dfd4b80a7a6683fe146ebBobby Georgescu                    s.titleRightMargin, mTitlePaint);
1811a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
182e24cc7208a6d3760a87dfd4b80a7a6683fe146ebBobby Georgescu            // draw count
1831a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            if (jc.isCancelled()) return null;
184e24cc7208a6d3760a87dfd4b80a7a6683fe146ebBobby Georgescu            x = labelWidth - s.titleRightMargin;
185e24cc7208a6d3760a87dfd4b80a7a6683fe146ebBobby Georgescu            y = (s.labelBackgroundHeight - s.countFontSize) / 2;
1861a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            drawText(canvas, x, y, count,
187e24cc7208a6d3760a87dfd4b80a7a6683fe146ebBobby Georgescu                    labelWidth - x , mCountPaint);
1881a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
1891a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            // draw the icon
1901a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            if (icon != null) {
1911a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                if (jc.isCancelled()) return null;
1921a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                float scale = (float) s.iconSize / icon.getWidth();
193c90a116a7fd65d41e8258dc7b9a14218649697e6Bobby Georgescu                canvas.translate(s.leftMargin, (s.labelBackgroundHeight -
194c90a116a7fd65d41e8258dc7b9a14218649697e6Bobby Georgescu                        Math.round(scale * icon.getHeight()))/2f);
1951a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                canvas.scale(scale, scale);
1961a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                canvas.drawBitmap(icon, 0, 0, null);
1971a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            }
1981a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
1991a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            return bitmap;
2001a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        }
2011a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    }
202d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin
203b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang    public void recycleLabel(Bitmap label) {
204f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu        GalleryBitmapPool.getInstance().put(label);
205d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    }
2061a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin}
207