1/*
2 * Copyright (C) 2008 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.internal.policy.impl;
18
19import android.graphics.drawable.BitmapDrawable;
20import android.graphics.drawable.Drawable;
21import android.graphics.drawable.PaintDrawable;
22import android.graphics.drawable.StateListDrawable;
23import android.graphics.Bitmap;
24import android.graphics.BlurMaskFilter;
25import android.graphics.Canvas;
26import android.graphics.ColorMatrix;
27import android.graphics.ColorMatrixColorFilter;
28import android.graphics.Paint;
29import android.graphics.PaintFlagsDrawFilter;
30import android.graphics.PixelFormat;
31import android.graphics.PorterDuff;
32import android.graphics.Rect;
33import android.graphics.RectF;
34import android.graphics.TableMaskFilter;
35import android.graphics.Typeface;
36import android.text.Layout.Alignment;
37import android.text.StaticLayout;
38import android.text.TextPaint;
39import android.util.DisplayMetrics;
40import android.util.Log;
41import android.content.res.Resources;
42import android.content.Context;
43
44/**
45 * Various utilities shared amongst the Launcher's classes.
46 */
47final class IconUtilities {
48    private static final String TAG = "IconUtilities";
49
50    private static final int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
51
52    private int mIconWidth = -1;
53    private int mIconHeight = -1;
54    private int mIconTextureWidth = -1;
55    private int mIconTextureHeight = -1;
56
57    private final Paint mPaint = new Paint();
58    private final Paint mBlurPaint = new Paint();
59    private final Paint mGlowColorPressedPaint = new Paint();
60    private final Paint mGlowColorFocusedPaint = new Paint();
61    private final Rect mOldBounds = new Rect();
62    private final Canvas mCanvas = new Canvas();
63    private final DisplayMetrics mDisplayMetrics;
64
65    private int mColorIndex = 0;
66
67    public IconUtilities(Context context) {
68        final Resources resources = context.getResources();
69        DisplayMetrics metrics = mDisplayMetrics = resources.getDisplayMetrics();
70        final float density = metrics.density;
71        final float blurPx = 5 * density;
72
73        mIconWidth = mIconHeight = (int) resources.getDimension(android.R.dimen.app_icon_size);
74        mIconTextureWidth = mIconTextureHeight = mIconWidth + (int)(blurPx*2);
75
76        mBlurPaint.setMaskFilter(new BlurMaskFilter(blurPx, BlurMaskFilter.Blur.NORMAL));
77        mGlowColorPressedPaint.setColor(0xffffc300);
78        mGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
79        mGlowColorFocusedPaint.setColor(0xffff8e00);
80        mGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
81
82        ColorMatrix cm = new ColorMatrix();
83        cm.setSaturation(0.2f);
84
85        mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
86                Paint.FILTER_BITMAP_FLAG));
87    }
88
89    public Drawable createIconDrawable(Drawable src) {
90        Bitmap scaled = createIconBitmap(src);
91
92        StateListDrawable result = new StateListDrawable();
93
94        result.addState(new int[] { android.R.attr.state_focused },
95                new BitmapDrawable(createSelectedBitmap(scaled, false)));
96        result.addState(new int[] { android.R.attr.state_pressed },
97                new BitmapDrawable(createSelectedBitmap(scaled, true)));
98        result.addState(new int[0], new BitmapDrawable(scaled));
99
100        result.setBounds(0, 0, mIconTextureWidth, mIconTextureHeight);
101        return result;
102    }
103
104    /**
105     * Returns a bitmap suitable for the all apps view.  The bitmap will be a power
106     * of two sized ARGB_8888 bitmap that can be used as a gl texture.
107     */
108    private Bitmap createIconBitmap(Drawable icon) {
109        int width = mIconWidth;
110        int height = mIconHeight;
111
112        if (icon instanceof PaintDrawable) {
113            PaintDrawable painter = (PaintDrawable) icon;
114            painter.setIntrinsicWidth(width);
115            painter.setIntrinsicHeight(height);
116        } else if (icon instanceof BitmapDrawable) {
117            // Ensure the bitmap has a density.
118            BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
119            Bitmap bitmap = bitmapDrawable.getBitmap();
120            if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
121                bitmapDrawable.setTargetDensity(mDisplayMetrics);
122            }
123        }
124        int sourceWidth = icon.getIntrinsicWidth();
125        int sourceHeight = icon.getIntrinsicHeight();
126
127        if (sourceWidth > 0 && sourceWidth > 0) {
128            // There are intrinsic sizes.
129            if (width < sourceWidth || height < sourceHeight) {
130                // It's too big, scale it down.
131                final float ratio = (float) sourceWidth / sourceHeight;
132                if (sourceWidth > sourceHeight) {
133                    height = (int) (width / ratio);
134                } else if (sourceHeight > sourceWidth) {
135                    width = (int) (height * ratio);
136                }
137            } else if (sourceWidth < width && sourceHeight < height) {
138                // It's small, use the size they gave us.
139                width = sourceWidth;
140                height = sourceHeight;
141            }
142        }
143
144        // no intrinsic size --> use default size
145        int textureWidth = mIconTextureWidth;
146        int textureHeight = mIconTextureHeight;
147
148        final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
149                Bitmap.Config.ARGB_8888);
150        final Canvas canvas = mCanvas;
151        canvas.setBitmap(bitmap);
152
153        final int left = (textureWidth-width) / 2;
154        final int top = (textureHeight-height) / 2;
155
156        if (false) {
157            // draw a big box for the icon for debugging
158            canvas.drawColor(sColors[mColorIndex]);
159            if (++mColorIndex >= sColors.length) mColorIndex = 0;
160            Paint debugPaint = new Paint();
161            debugPaint.setColor(0xffcccc00);
162            canvas.drawRect(left, top, left+width, top+height, debugPaint);
163        }
164
165        mOldBounds.set(icon.getBounds());
166        icon.setBounds(left, top, left+width, top+height);
167        icon.draw(canvas);
168        icon.setBounds(mOldBounds);
169
170        return bitmap;
171    }
172
173    private Bitmap createSelectedBitmap(Bitmap src, boolean pressed) {
174        final Bitmap result = Bitmap.createBitmap(mIconTextureWidth, mIconTextureHeight,
175                Bitmap.Config.ARGB_8888);
176        final Canvas dest = new Canvas(result);
177
178        dest.drawColor(0, PorterDuff.Mode.CLEAR);
179
180        int[] xy = new int[2];
181        Bitmap mask = src.extractAlpha(mBlurPaint, xy);
182
183        dest.drawBitmap(mask, xy[0], xy[1],
184                pressed ? mGlowColorPressedPaint : mGlowColorFocusedPaint);
185
186        mask.recycle();
187
188        dest.drawBitmap(src, 0, 0, mPaint);
189
190        return result;
191    }
192}
193