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