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