blob: e227569d75c96dbf40e8352e9dd1870f78448daa [file] [log] [blame]
Winson Chungb3347bb2010-08-19 14:51:28 -07001/*
2 * Copyright (C) 2010 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.launcher2;
18
19import android.content.Context;
Winson Chung241c3b42010-08-25 16:53:03 -070020import android.content.pm.PackageManager;
21import android.content.pm.ResolveInfo;
Winson Chungb3347bb2010-08-19 14:51:28 -070022import android.content.res.Resources;
23import android.graphics.Bitmap;
24import android.graphics.BlurMaskFilter;
25import android.graphics.Canvas;
Winson Chungb3347bb2010-08-19 14:51:28 -070026import android.graphics.Matrix;
27import android.graphics.Paint;
28import android.graphics.PointF;
29import android.graphics.PorterDuff;
30import android.graphics.PorterDuffXfermode;
31import android.graphics.Rect;
32import android.graphics.Region.Op;
Winson Chung03c568e2010-08-19 17:16:59 -070033import android.graphics.drawable.Drawable;
Winson Chungb3347bb2010-08-19 14:51:28 -070034import android.util.AttributeSet;
35import android.util.DisplayMetrics;
Winson Chung241c3b42010-08-25 16:53:03 -070036import android.util.Log;
Winson Chung03c568e2010-08-19 17:16:59 -070037import android.widget.Checkable;
Winson Chungb3347bb2010-08-19 14:51:28 -070038import android.widget.TextView;
39
Winson Chung241c3b42010-08-25 16:53:03 -070040import com.android.launcher2.PagedView.PagedViewIconCache;
41
Winson Chungb3347bb2010-08-19 14:51:28 -070042class HolographicOutlineHelper {
43 private final Paint mHolographicPaint = new Paint();
44 private final Paint mBlurPaint = new Paint();
45 private final Paint mErasePaint = new Paint();
46 private static final Matrix mIdentity = new Matrix();
47 private static final float STROKE_WIDTH = 6.0f;
48 private static final float BLUR_FACTOR = 3.5f;
49
Winson Chung03c568e2010-08-19 17:16:59 -070050 public static final int HOLOGRAPHIC_BLUE = 0xFF6699FF;
51 public static final int HOLOGRAPHIC_GREEN = 0xFF66FF66;
52
Winson Chungb3347bb2010-08-19 14:51:28 -070053 HolographicOutlineHelper(float density) {
Winson Chung03c568e2010-08-19 17:16:59 -070054 mHolographicPaint.setColor(HOLOGRAPHIC_BLUE);
Winson Chungb3347bb2010-08-19 14:51:28 -070055 mHolographicPaint.setFilterBitmap(true);
56 mHolographicPaint.setAntiAlias(true);
57 mBlurPaint.setMaskFilter(new BlurMaskFilter(BLUR_FACTOR * density,
58 BlurMaskFilter.Blur.OUTER));
59 mBlurPaint.setFilterBitmap(true);
60 mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
61 mErasePaint.setFilterBitmap(true);
62 mErasePaint.setAntiAlias(true);
63 }
64
65 private float cubic(float r) {
66 return (float) (Math.pow(r-1, 3) + 1);
67 }
68
69 /**
70 * Returns the interpolated holographic highlight alpha for the effect we want when scrolling
71 * pages.
72 */
73 public float highlightAlphaInterpolator(float r) {
74 final float pivot = 0.3f;
75 if (r < pivot) {
76 return Math.max(0.5f, 0.65f*cubic(r/pivot));
77 } else {
78 return Math.min(1.0f, 0.65f*cubic(1 - (r-pivot)/(1-pivot)));
79 }
80 }
81
82 /**
83 * Returns the interpolated view alpha for the effect we want when scrolling pages.
84 */
85 public float viewAlphaInterpolator(float r) {
86 final float pivot = 0.6f;
87 if (r < pivot) {
88 return r/pivot;
89 } else {
90 return 1.0f;
91 }
92 }
93
94 /**
Winson Chung03c568e2010-08-19 17:16:59 -070095 * Sets the color of the holographic paint to be used when applying the outline/blur.
96 */
97 void setColor(int color) {
98 mHolographicPaint.setColor(color);
99 }
100
101 /**
Winson Chungb3347bb2010-08-19 14:51:28 -0700102 * Applies an outline to whatever is currently drawn in the specified bitmap.
103 */
104 void applyOutline(Bitmap srcDst, Canvas srcDstCanvas, PointF offset) {
105 Bitmap mask = srcDst.extractAlpha();
106 Matrix m = new Matrix();
107 final int width = srcDst.getWidth();
108 final int height = srcDst.getHeight();
109 float xScale = STROKE_WIDTH*2.0f/width;
110 float yScale = STROKE_WIDTH*2.0f/height;
111 m.preScale(1+xScale, 1+yScale, (width / 2.0f) + offset.x,
112 (height / 2.0f) + offset.y);
113
114 srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
115 srcDstCanvas.drawBitmap(mask, m, mHolographicPaint);
116 srcDstCanvas.drawBitmap(mask, mIdentity, mErasePaint);
117 mask.recycle();
118 }
119
120 /**
121 * Applies an blur to whatever is currently drawn in the specified bitmap.
122 */
123 void applyBlur(Bitmap srcDst, Canvas srcDstCanvas) {
124 int[] xy = new int[2];
125 Bitmap mask = srcDst.extractAlpha(mBlurPaint, xy);
126 srcDstCanvas.drawBitmap(mask, xy[0], xy[1], mHolographicPaint);
127 mask.recycle();
128 }
129}
130
131/**
132 * An icon on a PagedView, specifically for items in the launcher's paged view (with compound
133 * drawables on the top).
134 */
Winson Chung03c568e2010-08-19 17:16:59 -0700135public class PagedViewIcon extends TextView implements Checkable {
Winson Chungb3347bb2010-08-19 14:51:28 -0700136 private static final String TAG = "PagedViewIcon";
137
138 // holographic outline
139 private final Paint mPaint = new Paint();
140 private static HolographicOutlineHelper sHolographicOutlineHelper;
141 private Bitmap mHolographicOutline;
142 private Canvas mHolographicOutlineCanvas;
143 private boolean mIsHolographicUpdatePass;
144 private Rect mDrawableClipRect;
145
Winson Chung241c3b42010-08-25 16:53:03 -0700146 private Object mIconCacheKey;
147 private PagedViewIconCache mIconCache;
148
Winson Chungb3347bb2010-08-19 14:51:28 -0700149 private int mAlpha;
150 private int mHolographicAlpha;
151
Winson Chung03c568e2010-08-19 17:16:59 -0700152 private boolean mIsChecked;
153
Winson Chungb3347bb2010-08-19 14:51:28 -0700154 public PagedViewIcon(Context context) {
155 this(context, null);
156 }
157
158 public PagedViewIcon(Context context, AttributeSet attrs) {
159 this(context, attrs, 0);
160 }
161
162 public PagedViewIcon(Context context, AttributeSet attrs, int defStyle) {
163 super(context, attrs, defStyle);
164
165 if (sHolographicOutlineHelper == null) {
166 final Resources resources = context.getResources();
167 final DisplayMetrics metrics = resources.getDisplayMetrics();
168 final float density = metrics.density;
169 sHolographicOutlineHelper = new HolographicOutlineHelper(density);
170 }
171 mDrawableClipRect = new Rect();
172
173 setFocusable(true);
174 setBackgroundDrawable(null);
175 }
176
Winson Chung241c3b42010-08-25 16:53:03 -0700177 public void applyFromApplicationInfo(ApplicationInfo info, PagedViewIconCache cache) {
178 mIconCache = cache;
179 mIconCacheKey = info;
180 mHolographicOutline = mIconCache.getOutline(mIconCacheKey);
181
182 setCompoundDrawablesWithIntrinsicBounds(null,
183 new FastBitmapDrawable(info.iconBitmap), null, null);
184 setText(info.title);
185 setTag(info);
186 }
187
188 public void applyFromResolveInfo(ResolveInfo info, PackageManager packageManager,
189 PagedViewIconCache cache) {
190 mIconCache = cache;
191 mIconCacheKey = info;
192 mHolographicOutline = mIconCache.getOutline(mIconCacheKey);
193
194 Drawable image = info.loadIcon(packageManager);
195 image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
196 setCompoundDrawablesWithIntrinsicBounds(null, image, null, null);
197 setText(info.loadLabel(packageManager));
198 setTag(info);
199 }
200
Winson Chungb3347bb2010-08-19 14:51:28 -0700201 @Override
202 public void setAlpha(float alpha) {
203 final float viewAlpha = sHolographicOutlineHelper.viewAlphaInterpolator(alpha);
Winson Chungb3347bb2010-08-19 14:51:28 -0700204 final float holographicAlpha = sHolographicOutlineHelper.highlightAlphaInterpolator(alpha);
Winson Chungaffd7b42010-08-20 15:11:56 -0700205 mAlpha = (int) (viewAlpha * 255);
Winson Chungb3347bb2010-08-19 14:51:28 -0700206 mHolographicAlpha = (int) (holographicAlpha * 255);
Winson Chungb3347bb2010-08-19 14:51:28 -0700207 super.setAlpha(viewAlpha);
208 }
209
210 @Override
211 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
212 super.onLayout(changed, left, top, right, bottom);
213
214 if (mHolographicOutline == null) {
215 final PointF offset = new PointF(0,
216 -(getCompoundPaddingBottom() + getCompoundPaddingTop())/2.0f);
217
218 // update the clipping rect to be used in the holographic pass below
219 getDrawingRect(mDrawableClipRect);
220 mDrawableClipRect.bottom = getPaddingTop() + getCompoundPaddingTop();
221
222 // set a flag to indicate that we are going to draw the view at full alpha with the text
223 // clipped for the generation of the holographic icon
224 mIsHolographicUpdatePass = true;
225 mHolographicOutline = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
226 Bitmap.Config.ARGB_8888);
227 mHolographicOutlineCanvas = new Canvas(mHolographicOutline);
228 mHolographicOutlineCanvas.concat(getMatrix());
229 draw(mHolographicOutlineCanvas);
Winson Chung03c568e2010-08-19 17:16:59 -0700230 sHolographicOutlineHelper.setColor(HolographicOutlineHelper.HOLOGRAPHIC_BLUE);
231 sHolographicOutlineHelper.applyOutline(mHolographicOutline, mHolographicOutlineCanvas,
Winson Chungb3347bb2010-08-19 14:51:28 -0700232 offset);
233 sHolographicOutlineHelper.applyBlur(mHolographicOutline, mHolographicOutlineCanvas);
234 mIsHolographicUpdatePass = false;
Winson Chung241c3b42010-08-25 16:53:03 -0700235 mIconCache.addOutline(mIconCacheKey, mHolographicOutline);
Winson Chungb3347bb2010-08-19 14:51:28 -0700236 }
237 }
238
Winson Chungb3347bb2010-08-19 14:51:28 -0700239 @Override
240 protected void onDraw(Canvas canvas) {
Winson Chungaffd7b42010-08-20 15:11:56 -0700241 // draw the view itself
Winson Chungb3347bb2010-08-19 14:51:28 -0700242 if (mIsHolographicUpdatePass) {
243 // only clip to the text view (restore its alpha so that we get a proper outline)
244 canvas.save();
245 canvas.clipRect(mDrawableClipRect, Op.REPLACE);
Winson Chungaffd7b42010-08-20 15:11:56 -0700246 final float alpha = getAlpha();
247 super.setAlpha(1.0f);
Winson Chungb3347bb2010-08-19 14:51:28 -0700248 super.onDraw(canvas);
Winson Chungaffd7b42010-08-20 15:11:56 -0700249 super.setAlpha(alpha);
Winson Chungb3347bb2010-08-19 14:51:28 -0700250 canvas.restore();
251 } else {
252 if (mAlpha > 0) {
253 super.onDraw(canvas);
254 }
255 }
256
257 if (!mIsHolographicUpdatePass && mHolographicOutline != null && mHolographicAlpha > 0) {
258 mPaint.setAlpha(mHolographicAlpha);
259 canvas.drawBitmap(mHolographicOutline, 0, 0, mPaint);
260 }
261 }
Winson Chung03c568e2010-08-19 17:16:59 -0700262
263 @Override
264 public boolean isChecked() {
265 return mIsChecked;
266 }
267
268 @Override
269 public void setChecked(boolean checked) {
270 mIsChecked = checked;
271 invalidate();
272 }
273
274 @Override
275 public void toggle() {
276 setChecked(!mIsChecked);
277 }
Winson Chungb3347bb2010-08-19 14:51:28 -0700278}