blob: 625c467103bf3a88873d538f9bba00bea68eab8e [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;
26
27public class HolographicOutlineHelper {
Michael Jurka5f1c5092010-09-03 14:15:02 -070028 private final Paint mHolographicPaint = new Paint();
Joe Onorato4be866d2010-10-10 11:26:02 -070029 private final Paint mBlurPaint = new Paint();
Michael Jurka5f1c5092010-09-03 14:15:02 -070030 private final Paint mErasePaint = new Paint();
Michael Jurka5f1c5092010-09-03 14:15:02 -070031
Michael Jurka38b4f7c2010-12-14 16:46:39 -080032 public static final int MAX_OUTER_BLUR_RADIUS;
Winson Chung1908d072011-02-24 18:09:44 -080033 public static final int MIN_OUTER_BLUR_RADIUS;
Joe Onorato4be866d2010-10-10 11:26:02 -070034
Michael Jurka38b4f7c2010-12-14 16:46:39 -080035 private static final BlurMaskFilter sExtraThickOuterBlurMaskFilter;
Patrick Dubroy8e58e912010-10-14 13:21:48 -070036 private static final BlurMaskFilter sThickOuterBlurMaskFilter;
37 private static final BlurMaskFilter sMediumOuterBlurMaskFilter;
38 private static final BlurMaskFilter sThinOuterBlurMaskFilter;
39 private static final BlurMaskFilter sThickInnerBlurMaskFilter;
Michael Jurka38b4f7c2010-12-14 16:46:39 -080040 private static final BlurMaskFilter sExtraThickInnerBlurMaskFilter;
Adam Cohen5bb50bd2010-12-03 11:39:55 -080041 private static final BlurMaskFilter sMediumInnerBlurMaskFilter;
42
43 private static final int THICK = 0;
44 private static final int MEDIUM = 1;
Michael Jurka38b4f7c2010-12-14 16:46:39 -080045 private static final int EXTRA_THICK = 2;
Patrick Dubroy8e58e912010-10-14 13:21:48 -070046
47 static {
48 final float scale = LauncherApplication.getScreenDensity();
49
Winson Chung1908d072011-02-24 18:09:44 -080050 MIN_OUTER_BLUR_RADIUS = (int) (scale * 1.0f);
Michael Jurka38b4f7c2010-12-14 16:46:39 -080051 MAX_OUTER_BLUR_RADIUS = (int) (scale * 12.0f);
Patrick Dubroy8e58e912010-10-14 13:21:48 -070052
Michael Jurka38b4f7c2010-12-14 16:46:39 -080053 sExtraThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 12.0f, BlurMaskFilter.Blur.OUTER);
54 sThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.OUTER);
Patrick Dubroy8e58e912010-10-14 13:21:48 -070055 sMediumOuterBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.OUTER);
56 sThinOuterBlurMaskFilter = new BlurMaskFilter(scale * 1.0f, BlurMaskFilter.Blur.OUTER);
Michael Jurka38b4f7c2010-12-14 16:46:39 -080057 sExtraThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.NORMAL);
Patrick Dubroy8e58e912010-10-14 13:21:48 -070058 sThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL);
Adam Cohen5bb50bd2010-12-03 11:39:55 -080059 sMediumInnerBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.NORMAL);
Patrick Dubroy8e58e912010-10-14 13:21:48 -070060 }
Joe Onorato4be866d2010-10-10 11:26:02 -070061
Winson Chung64a3cd42010-09-17 16:47:33 -070062 HolographicOutlineHelper() {
Michael Jurka5f1c5092010-09-03 14:15:02 -070063 mHolographicPaint.setFilterBitmap(true);
64 mHolographicPaint.setAntiAlias(true);
Joe Onorato4be866d2010-10-10 11:26:02 -070065 mBlurPaint.setFilterBitmap(true);
66 mBlurPaint.setAntiAlias(true);
Michael Jurka5f1c5092010-09-03 14:15:02 -070067 mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
68 mErasePaint.setFilterBitmap(true);
69 mErasePaint.setAntiAlias(true);
70 }
71
Michael Jurka5f1c5092010-09-03 14:15:02 -070072 /**
73 * Returns the interpolated holographic highlight alpha for the effect we want when scrolling
74 * pages.
75 */
Winson Chungb44b5242011-06-13 11:32:14 -070076 public static float highlightAlphaInterpolator(float r) {
77 float maxAlpha = 0.6f;
Winson Chunge8878e32010-09-15 20:37:09 -070078 return (float) Math.pow(maxAlpha * (1.0f - r), 1.5f);
Michael Jurka5f1c5092010-09-03 14:15:02 -070079 }
80
81 /**
82 * Returns the interpolated view alpha for the effect we want when scrolling pages.
83 */
Winson Chungb44b5242011-06-13 11:32:14 -070084 public static float viewAlphaInterpolator(float r) {
Winson Chunge8878e32010-09-15 20:37:09 -070085 final float pivot = 0.95f;
Michael Jurka5f1c5092010-09-03 14:15:02 -070086 if (r < pivot) {
Winson Chunge8878e32010-09-15 20:37:09 -070087 return (float) Math.pow(r / pivot, 1.5f);
Michael Jurka5f1c5092010-09-03 14:15:02 -070088 } else {
89 return 1.0f;
90 }
91 }
92
Patrick Dubroy8e58e912010-10-14 13:21:48 -070093 /**
Winson Chung64a3cd42010-09-17 16:47:33 -070094 * Applies a more expensive and accurate outline to whatever is currently drawn in a specified
95 * bitmap.
Michael Jurka5f1c5092010-09-03 14:15:02 -070096 */
Winson Chung64a3cd42010-09-17 16:47:33 -070097 void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
Adam Cohen5bb50bd2010-12-03 11:39:55 -080098 int outlineColor, int thickness) {
Michael Jurka8c3339b2012-06-14 16:18:21 -070099 applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true,
Peter Ng8db70002011-10-25 15:40:08 -0700100 thickness);
101 }
102 void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
Michael Jurka8c3339b2012-06-14 16:18:21 -0700103 int outlineColor, boolean clipAlpha, int thickness) {
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800104
105 // We start by removing most of the alpha channel so as to ignore shadows, and
106 // other types of partial transparency when defining the shape of the object
Michael Jurka8c3339b2012-06-14 16:18:21 -0700107 if (clipAlpha) {
108 int[] srcBuffer = new int[srcDst.getWidth() * srcDst.getHeight()];
109 srcDst.getPixels(srcBuffer,
110 0, srcDst.getWidth(), 0, 0, srcDst.getWidth(), srcDst.getHeight());
111 for (int i = 0; i < srcBuffer.length; i++) {
112 final int alpha = srcBuffer[i] >>> 24;
113 if (alpha < 188) {
114 srcBuffer[i] = 0;
115 }
116 }
117 srcDst.setPixels(srcBuffer,
118 0, srcDst.getWidth(), 0, 0, srcDst.getWidth(), srcDst.getHeight());
Peter Ng8db70002011-10-25 15:40:08 -0700119 }
Michael Jurka8c3339b2012-06-14 16:18:21 -0700120 Bitmap glowShape = srcDst.extractAlpha();
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800121
Winson Chung64a3cd42010-09-17 16:47:33 -0700122 // calculate the outer blur first
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800123 BlurMaskFilter outerBlurMaskFilter;
124 switch (thickness) {
125 case EXTRA_THICK:
126 outerBlurMaskFilter = sExtraThickOuterBlurMaskFilter;
127 break;
128 case THICK:
129 outerBlurMaskFilter = sThickOuterBlurMaskFilter;
130 break;
131 case MEDIUM:
132 outerBlurMaskFilter = sMediumOuterBlurMaskFilter;
133 break;
134 default:
135 throw new RuntimeException("Invalid blur thickness");
136 }
137 mBlurPaint.setMaskFilter(outerBlurMaskFilter);
Winson Chung64a3cd42010-09-17 16:47:33 -0700138 int[] outerBlurOffset = new int[2];
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800139 Bitmap thickOuterBlur = glowShape.extractAlpha(mBlurPaint, outerBlurOffset);
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800140 if (thickness == EXTRA_THICK) {
141 mBlurPaint.setMaskFilter(sMediumOuterBlurMaskFilter);
142 } else {
143 mBlurPaint.setMaskFilter(sThinOuterBlurMaskFilter);
144 }
145
146 int[] brightOutlineOffset = new int[2];
147 Bitmap brightOutline = glowShape.extractAlpha(mBlurPaint, brightOutlineOffset);
Winson Chung64a3cd42010-09-17 16:47:33 -0700148
149 // calculate the inner blur
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800150 srcDstCanvas.setBitmap(glowShape);
Winson Chung64a3cd42010-09-17 16:47:33 -0700151 srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT);
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800152 BlurMaskFilter innerBlurMaskFilter;
153 switch (thickness) {
154 case EXTRA_THICK:
155 innerBlurMaskFilter = sExtraThickInnerBlurMaskFilter;
156 break;
157 case THICK:
158 innerBlurMaskFilter = sThickInnerBlurMaskFilter;
159 break;
160 case MEDIUM:
161 innerBlurMaskFilter = sMediumInnerBlurMaskFilter;
162 break;
163 default:
164 throw new RuntimeException("Invalid blur thickness");
165 }
166 mBlurPaint.setMaskFilter(innerBlurMaskFilter);
Winson Chung64a3cd42010-09-17 16:47:33 -0700167 int[] thickInnerBlurOffset = new int[2];
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800168 Bitmap thickInnerBlur = glowShape.extractAlpha(mBlurPaint, thickInnerBlurOffset);
Winson Chung64a3cd42010-09-17 16:47:33 -0700169
170 // mask out the inner blur
171 srcDstCanvas.setBitmap(thickInnerBlur);
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800172 srcDstCanvas.drawBitmap(glowShape, -thickInnerBlurOffset[0],
Winson Chung64a3cd42010-09-17 16:47:33 -0700173 -thickInnerBlurOffset[1], mErasePaint);
174 srcDstCanvas.drawRect(0, 0, -thickInnerBlurOffset[0], thickInnerBlur.getHeight(),
175 mErasePaint);
176 srcDstCanvas.drawRect(0, 0, thickInnerBlur.getWidth(), -thickInnerBlurOffset[1],
177 mErasePaint);
178
179 // draw the inner and outer blur
180 srcDstCanvas.setBitmap(srcDst);
Michael Jurka2a9e7062011-01-14 15:48:04 -0800181 srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
Michael Jurka5f1c5092010-09-03 14:15:02 -0700182 mHolographicPaint.setColor(color);
Winson Chung64a3cd42010-09-17 16:47:33 -0700183 srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1],
184 mHolographicPaint);
185 srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1],
186 mHolographicPaint);
Michael Jurka5f1c5092010-09-03 14:15:02 -0700187
Winson Chung64a3cd42010-09-17 16:47:33 -0700188 // draw the bright outline
189 mHolographicPaint.setColor(outlineColor);
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800190 srcDstCanvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1],
Winson Chung64a3cd42010-09-17 16:47:33 -0700191 mHolographicPaint);
Michael Jurka5f1c5092010-09-03 14:15:02 -0700192
Winson Chung64a3cd42010-09-17 16:47:33 -0700193 // cleanup
Adam Cohenaaf473c2011-08-03 12:02:47 -0700194 srcDstCanvas.setBitmap(null);
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800195 brightOutline.recycle();
Winson Chung64a3cd42010-09-17 16:47:33 -0700196 thickOuterBlur.recycle();
197 thickInnerBlur.recycle();
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800198 glowShape.recycle();
Michael Jurka5f1c5092010-09-03 14:15:02 -0700199 }
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800200
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800201 void applyExtraThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
202 int outlineColor) {
203 applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, EXTRA_THICK);
204 }
205
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800206 void applyThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
207 int outlineColor) {
208 applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, THICK);
209 }
210
211 void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
Michael Jurka8c3339b2012-06-14 16:18:21 -0700212 int outlineColor, boolean clipAlpha) {
213 applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, clipAlpha,
Peter Ng8db70002011-10-25 15:40:08 -0700214 MEDIUM);
215 }
216
217 void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800218 int outlineColor) {
219 applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, MEDIUM);
220 }
221
Winson Chung7da10252010-10-28 16:07:04 -0700222}