blob: 56d194d4ebd9151625c661a50ae5204f09f322c4 [file] [log] [blame]
Michael Jurka5f1c5092010-09-03 14:15:02 -07001/*
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.launcher2;
18
19import android.graphics.Bitmap;
20import android.graphics.BlurMaskFilter;
21import android.graphics.Canvas;
Joe Onorato4be866d2010-10-10 11:26:02 -070022import android.graphics.MaskFilter;
Michael Jurka5f1c5092010-09-03 14:15:02 -070023import android.graphics.Paint;
Michael Jurka5f1c5092010-09-03 14:15:02 -070024import android.graphics.PorterDuff;
25import android.graphics.PorterDuffXfermode;
Joe Onorato4be866d2010-10-10 11:26:02 -070026import android.graphics.TableMaskFilter;
Michael Jurka5f1c5092010-09-03 14:15:02 -070027
28public class HolographicOutlineHelper {
Michael Jurka5f1c5092010-09-03 14:15:02 -070029 private final Paint mHolographicPaint = new Paint();
Joe Onorato4be866d2010-10-10 11:26:02 -070030 private final Paint mBlurPaint = new Paint();
Michael Jurka5f1c5092010-09-03 14:15:02 -070031 private final Paint mErasePaint = new Paint();
Adam Cohen5bb50bd2010-12-03 11:39:55 -080032 private final Paint mAlphaClipPaint = new Paint();
Michael Jurka5f1c5092010-09-03 14:15:02 -070033
Michael Jurka38b4f7c2010-12-14 16:46:39 -080034 public static final int MAX_OUTER_BLUR_RADIUS;
Winson Chung1908d072011-02-24 18:09:44 -080035 public static final int MIN_OUTER_BLUR_RADIUS;
Joe Onorato4be866d2010-10-10 11:26:02 -070036
Michael Jurka38b4f7c2010-12-14 16:46:39 -080037 private static final BlurMaskFilter sExtraThickOuterBlurMaskFilter;
Patrick Dubroy8e58e912010-10-14 13:21:48 -070038 private static final BlurMaskFilter sThickOuterBlurMaskFilter;
39 private static final BlurMaskFilter sMediumOuterBlurMaskFilter;
40 private static final BlurMaskFilter sThinOuterBlurMaskFilter;
41 private static final BlurMaskFilter sThickInnerBlurMaskFilter;
Michael Jurka38b4f7c2010-12-14 16:46:39 -080042 private static final BlurMaskFilter sExtraThickInnerBlurMaskFilter;
Adam Cohen5bb50bd2010-12-03 11:39:55 -080043 private static final BlurMaskFilter sMediumInnerBlurMaskFilter;
44
45 private static final int THICK = 0;
46 private static final int MEDIUM = 1;
Michael Jurka38b4f7c2010-12-14 16:46:39 -080047 private static final int EXTRA_THICK = 2;
Patrick Dubroy8e58e912010-10-14 13:21:48 -070048
49 static {
50 final float scale = LauncherApplication.getScreenDensity();
51
Winson Chung1908d072011-02-24 18:09:44 -080052 MIN_OUTER_BLUR_RADIUS = (int) (scale * 1.0f);
Michael Jurka38b4f7c2010-12-14 16:46:39 -080053 MAX_OUTER_BLUR_RADIUS = (int) (scale * 12.0f);
Patrick Dubroy8e58e912010-10-14 13:21:48 -070054
Michael Jurka38b4f7c2010-12-14 16:46:39 -080055 sExtraThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 12.0f, BlurMaskFilter.Blur.OUTER);
56 sThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.OUTER);
Patrick Dubroy8e58e912010-10-14 13:21:48 -070057 sMediumOuterBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.OUTER);
58 sThinOuterBlurMaskFilter = new BlurMaskFilter(scale * 1.0f, BlurMaskFilter.Blur.OUTER);
Michael Jurka38b4f7c2010-12-14 16:46:39 -080059 sExtraThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.NORMAL);
Patrick Dubroy8e58e912010-10-14 13:21:48 -070060 sThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL);
Adam Cohen5bb50bd2010-12-03 11:39:55 -080061 sMediumInnerBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.NORMAL);
Patrick Dubroy8e58e912010-10-14 13:21:48 -070062 }
Joe Onorato4be866d2010-10-10 11:26:02 -070063
Joe Onorato4be866d2010-10-10 11:26:02 -070064 private int[] mTempOffset = new int[2];
Michael Jurka5f1c5092010-09-03 14:15:02 -070065
Winson Chung64a3cd42010-09-17 16:47:33 -070066 HolographicOutlineHelper() {
Michael Jurka5f1c5092010-09-03 14:15:02 -070067 mHolographicPaint.setFilterBitmap(true);
68 mHolographicPaint.setAntiAlias(true);
Joe Onorato4be866d2010-10-10 11:26:02 -070069 mBlurPaint.setFilterBitmap(true);
70 mBlurPaint.setAntiAlias(true);
Michael Jurka5f1c5092010-09-03 14:15:02 -070071 mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
72 mErasePaint.setFilterBitmap(true);
73 mErasePaint.setAntiAlias(true);
Adam Cohen5bb50bd2010-12-03 11:39:55 -080074 MaskFilter alphaClipTable = TableMaskFilter.CreateClipTable(180, 255);
75 mAlphaClipPaint.setMaskFilter(alphaClipTable);
Michael Jurka5f1c5092010-09-03 14:15:02 -070076 }
77
Michael Jurka5f1c5092010-09-03 14:15:02 -070078 /**
79 * Returns the interpolated holographic highlight alpha for the effect we want when scrolling
80 * pages.
81 */
Winson Chungb44b5242011-06-13 11:32:14 -070082 public static float highlightAlphaInterpolator(float r) {
83 float maxAlpha = 0.6f;
Winson Chunge8878e32010-09-15 20:37:09 -070084 return (float) Math.pow(maxAlpha * (1.0f - r), 1.5f);
Michael Jurka5f1c5092010-09-03 14:15:02 -070085 }
86
87 /**
88 * Returns the interpolated view alpha for the effect we want when scrolling pages.
89 */
Winson Chungb44b5242011-06-13 11:32:14 -070090 public static float viewAlphaInterpolator(float r) {
Winson Chunge8878e32010-09-15 20:37:09 -070091 final float pivot = 0.95f;
Michael Jurka5f1c5092010-09-03 14:15:02 -070092 if (r < pivot) {
Winson Chunge8878e32010-09-15 20:37:09 -070093 return (float) Math.pow(r / pivot, 1.5f);
Michael Jurka5f1c5092010-09-03 14:15:02 -070094 } else {
95 return 1.0f;
96 }
97 }
98
Patrick Dubroy8e58e912010-10-14 13:21:48 -070099 /**
Winson Chung64a3cd42010-09-17 16:47:33 -0700100 * Applies a more expensive and accurate outline to whatever is currently drawn in a specified
101 * bitmap.
Michael Jurka5f1c5092010-09-03 14:15:02 -0700102 */
Winson Chung64a3cd42010-09-17 16:47:33 -0700103 void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800104 int outlineColor, int thickness) {
Peter Ng8db70002011-10-25 15:40:08 -0700105 applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, mAlphaClipPaint,
106 thickness);
107 }
108 void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
109 int outlineColor, Paint alphaClipPaint, int thickness) {
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800110
111 // We start by removing most of the alpha channel so as to ignore shadows, and
112 // other types of partial transparency when defining the shape of the object
Peter Ng8db70002011-10-25 15:40:08 -0700113 if (alphaClipPaint == null) {
114 alphaClipPaint = mAlphaClipPaint;
115 }
116 Bitmap glowShape = srcDst.extractAlpha(alphaClipPaint, mTempOffset);
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800117
Winson Chung64a3cd42010-09-17 16:47:33 -0700118 // calculate the outer blur first
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800119 BlurMaskFilter outerBlurMaskFilter;
120 switch (thickness) {
121 case EXTRA_THICK:
122 outerBlurMaskFilter = sExtraThickOuterBlurMaskFilter;
123 break;
124 case THICK:
125 outerBlurMaskFilter = sThickOuterBlurMaskFilter;
126 break;
127 case MEDIUM:
128 outerBlurMaskFilter = sMediumOuterBlurMaskFilter;
129 break;
130 default:
131 throw new RuntimeException("Invalid blur thickness");
132 }
133 mBlurPaint.setMaskFilter(outerBlurMaskFilter);
Winson Chung64a3cd42010-09-17 16:47:33 -0700134 int[] outerBlurOffset = new int[2];
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800135 Bitmap thickOuterBlur = glowShape.extractAlpha(mBlurPaint, outerBlurOffset);
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800136 if (thickness == EXTRA_THICK) {
137 mBlurPaint.setMaskFilter(sMediumOuterBlurMaskFilter);
138 } else {
139 mBlurPaint.setMaskFilter(sThinOuterBlurMaskFilter);
140 }
141
142 int[] brightOutlineOffset = new int[2];
143 Bitmap brightOutline = glowShape.extractAlpha(mBlurPaint, brightOutlineOffset);
Winson Chung64a3cd42010-09-17 16:47:33 -0700144
145 // calculate the inner blur
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800146 srcDstCanvas.setBitmap(glowShape);
Winson Chung64a3cd42010-09-17 16:47:33 -0700147 srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT);
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800148 BlurMaskFilter innerBlurMaskFilter;
149 switch (thickness) {
150 case EXTRA_THICK:
151 innerBlurMaskFilter = sExtraThickInnerBlurMaskFilter;
152 break;
153 case THICK:
154 innerBlurMaskFilter = sThickInnerBlurMaskFilter;
155 break;
156 case MEDIUM:
157 innerBlurMaskFilter = sMediumInnerBlurMaskFilter;
158 break;
159 default:
160 throw new RuntimeException("Invalid blur thickness");
161 }
162 mBlurPaint.setMaskFilter(innerBlurMaskFilter);
Winson Chung64a3cd42010-09-17 16:47:33 -0700163 int[] thickInnerBlurOffset = new int[2];
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800164 Bitmap thickInnerBlur = glowShape.extractAlpha(mBlurPaint, thickInnerBlurOffset);
Winson Chung64a3cd42010-09-17 16:47:33 -0700165
166 // mask out the inner blur
167 srcDstCanvas.setBitmap(thickInnerBlur);
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800168 srcDstCanvas.drawBitmap(glowShape, -thickInnerBlurOffset[0],
Winson Chung64a3cd42010-09-17 16:47:33 -0700169 -thickInnerBlurOffset[1], mErasePaint);
170 srcDstCanvas.drawRect(0, 0, -thickInnerBlurOffset[0], thickInnerBlur.getHeight(),
171 mErasePaint);
172 srcDstCanvas.drawRect(0, 0, thickInnerBlur.getWidth(), -thickInnerBlurOffset[1],
173 mErasePaint);
174
175 // draw the inner and outer blur
176 srcDstCanvas.setBitmap(srcDst);
Michael Jurka2a9e7062011-01-14 15:48:04 -0800177 srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
Michael Jurka5f1c5092010-09-03 14:15:02 -0700178 mHolographicPaint.setColor(color);
Winson Chung64a3cd42010-09-17 16:47:33 -0700179 srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1],
180 mHolographicPaint);
181 srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1],
182 mHolographicPaint);
Michael Jurka5f1c5092010-09-03 14:15:02 -0700183
Winson Chung64a3cd42010-09-17 16:47:33 -0700184 // draw the bright outline
185 mHolographicPaint.setColor(outlineColor);
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800186 srcDstCanvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1],
Winson Chung64a3cd42010-09-17 16:47:33 -0700187 mHolographicPaint);
Michael Jurka5f1c5092010-09-03 14:15:02 -0700188
Winson Chung64a3cd42010-09-17 16:47:33 -0700189 // cleanup
Adam Cohenaaf473c2011-08-03 12:02:47 -0700190 srcDstCanvas.setBitmap(null);
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800191 brightOutline.recycle();
Winson Chung64a3cd42010-09-17 16:47:33 -0700192 thickOuterBlur.recycle();
193 thickInnerBlur.recycle();
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800194 glowShape.recycle();
Michael Jurka5f1c5092010-09-03 14:15:02 -0700195 }
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800196
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800197 void applyExtraThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
198 int outlineColor) {
199 applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, EXTRA_THICK);
200 }
201
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800202 void applyThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
203 int outlineColor) {
204 applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, THICK);
205 }
206
207 void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
Peter Ng8db70002011-10-25 15:40:08 -0700208 int outlineColor, Paint alphaClipPaint) {
209 applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, alphaClipPaint,
210 MEDIUM);
211 }
212
213 void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800214 int outlineColor) {
215 applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, MEDIUM);
216 }
217
Winson Chung7da10252010-10-28 16:07:04 -0700218}