blob: 2decc3d22825bd42b85e41c0dc1d36fefcf2ec2d [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
Daniel Sandler325dc232013-06-05 22:57:57 -040017package com.android.launcher3;
Michael Jurka5f1c5092010-09-03 14:15:02 -070018
19import android.graphics.Bitmap;
20import android.graphics.BlurMaskFilter;
21import android.graphics.Canvas;
Michael Jurka5f1c5092010-09-03 14:15:02 -070022import android.graphics.Paint;
Michael Jurka5f1c5092010-09-03 14:15:02 -070023import android.graphics.PorterDuff;
24import android.graphics.PorterDuffXfermode;
25
26public class HolographicOutlineHelper {
Michael Jurka5f1c5092010-09-03 14:15:02 -070027 private final Paint mHolographicPaint = new Paint();
Joe Onorato4be866d2010-10-10 11:26:02 -070028 private final Paint mBlurPaint = new Paint();
Michael Jurka5f1c5092010-09-03 14:15:02 -070029 private final Paint mErasePaint = new Paint();
Michael Jurka5f1c5092010-09-03 14:15:02 -070030
Michael Jurka38b4f7c2010-12-14 16:46:39 -080031 public static final int MAX_OUTER_BLUR_RADIUS;
Winson Chung1908d072011-02-24 18:09:44 -080032 public static final int MIN_OUTER_BLUR_RADIUS;
Joe Onorato4be866d2010-10-10 11:26:02 -070033
Michael Jurka38b4f7c2010-12-14 16:46:39 -080034 private static final BlurMaskFilter sExtraThickOuterBlurMaskFilter;
Patrick Dubroy8e58e912010-10-14 13:21:48 -070035 private static final BlurMaskFilter sThickOuterBlurMaskFilter;
36 private static final BlurMaskFilter sMediumOuterBlurMaskFilter;
37 private static final BlurMaskFilter sThinOuterBlurMaskFilter;
38 private static final BlurMaskFilter sThickInnerBlurMaskFilter;
Michael Jurka38b4f7c2010-12-14 16:46:39 -080039 private static final BlurMaskFilter sExtraThickInnerBlurMaskFilter;
Adam Cohen5bb50bd2010-12-03 11:39:55 -080040 private static final BlurMaskFilter sMediumInnerBlurMaskFilter;
41
42 private static final int THICK = 0;
43 private static final int MEDIUM = 1;
Michael Jurka38b4f7c2010-12-14 16:46:39 -080044 private static final int EXTRA_THICK = 2;
Patrick Dubroy8e58e912010-10-14 13:21:48 -070045
46 static {
47 final float scale = LauncherApplication.getScreenDensity();
48
Winson Chung1908d072011-02-24 18:09:44 -080049 MIN_OUTER_BLUR_RADIUS = (int) (scale * 1.0f);
Michael Jurka38b4f7c2010-12-14 16:46:39 -080050 MAX_OUTER_BLUR_RADIUS = (int) (scale * 12.0f);
Patrick Dubroy8e58e912010-10-14 13:21:48 -070051
Michael Jurka38b4f7c2010-12-14 16:46:39 -080052 sExtraThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 12.0f, BlurMaskFilter.Blur.OUTER);
53 sThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.OUTER);
Patrick Dubroy8e58e912010-10-14 13:21:48 -070054 sMediumOuterBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.OUTER);
55 sThinOuterBlurMaskFilter = new BlurMaskFilter(scale * 1.0f, BlurMaskFilter.Blur.OUTER);
Michael Jurka38b4f7c2010-12-14 16:46:39 -080056 sExtraThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.NORMAL);
Patrick Dubroy8e58e912010-10-14 13:21:48 -070057 sThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL);
Adam Cohen5bb50bd2010-12-03 11:39:55 -080058 sMediumInnerBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.NORMAL);
Patrick Dubroy8e58e912010-10-14 13:21:48 -070059 }
Joe Onorato4be866d2010-10-10 11:26:02 -070060
Winson Chung64a3cd42010-09-17 16:47:33 -070061 HolographicOutlineHelper() {
Michael Jurka5f1c5092010-09-03 14:15:02 -070062 mHolographicPaint.setFilterBitmap(true);
63 mHolographicPaint.setAntiAlias(true);
Joe Onorato4be866d2010-10-10 11:26:02 -070064 mBlurPaint.setFilterBitmap(true);
65 mBlurPaint.setAntiAlias(true);
Michael Jurka5f1c5092010-09-03 14:15:02 -070066 mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
67 mErasePaint.setFilterBitmap(true);
68 mErasePaint.setAntiAlias(true);
69 }
70
Michael Jurka5f1c5092010-09-03 14:15:02 -070071 /**
72 * Returns the interpolated holographic highlight alpha for the effect we want when scrolling
73 * pages.
74 */
Winson Chungb44b5242011-06-13 11:32:14 -070075 public static float highlightAlphaInterpolator(float r) {
76 float maxAlpha = 0.6f;
Winson Chunge8878e32010-09-15 20:37:09 -070077 return (float) Math.pow(maxAlpha * (1.0f - r), 1.5f);
Michael Jurka5f1c5092010-09-03 14:15:02 -070078 }
79
80 /**
81 * Returns the interpolated view alpha for the effect we want when scrolling pages.
82 */
Winson Chungb44b5242011-06-13 11:32:14 -070083 public static float viewAlphaInterpolator(float r) {
Winson Chunge8878e32010-09-15 20:37:09 -070084 final float pivot = 0.95f;
Michael Jurka5f1c5092010-09-03 14:15:02 -070085 if (r < pivot) {
Winson Chunge8878e32010-09-15 20:37:09 -070086 return (float) Math.pow(r / pivot, 1.5f);
Michael Jurka5f1c5092010-09-03 14:15:02 -070087 } else {
88 return 1.0f;
89 }
90 }
91
Patrick Dubroy8e58e912010-10-14 13:21:48 -070092 /**
Winson Chung64a3cd42010-09-17 16:47:33 -070093 * Applies a more expensive and accurate outline to whatever is currently drawn in a specified
94 * bitmap.
Michael Jurka5f1c5092010-09-03 14:15:02 -070095 */
Winson Chung64a3cd42010-09-17 16:47:33 -070096 void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
Adam Cohen5bb50bd2010-12-03 11:39:55 -080097 int outlineColor, int thickness) {
Michael Jurka8c3339b2012-06-14 16:18:21 -070098 applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true,
Peter Ng8db70002011-10-25 15:40:08 -070099 thickness);
100 }
101 void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
Michael Jurka8c3339b2012-06-14 16:18:21 -0700102 int outlineColor, boolean clipAlpha, int thickness) {
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800103
104 // We start by removing most of the alpha channel so as to ignore shadows, and
105 // other types of partial transparency when defining the shape of the object
Michael Jurka8c3339b2012-06-14 16:18:21 -0700106 if (clipAlpha) {
107 int[] srcBuffer = new int[srcDst.getWidth() * srcDst.getHeight()];
108 srcDst.getPixels(srcBuffer,
109 0, srcDst.getWidth(), 0, 0, srcDst.getWidth(), srcDst.getHeight());
110 for (int i = 0; i < srcBuffer.length; i++) {
111 final int alpha = srcBuffer[i] >>> 24;
112 if (alpha < 188) {
113 srcBuffer[i] = 0;
114 }
115 }
116 srcDst.setPixels(srcBuffer,
117 0, srcDst.getWidth(), 0, 0, srcDst.getWidth(), srcDst.getHeight());
Peter Ng8db70002011-10-25 15:40:08 -0700118 }
Michael Jurka8c3339b2012-06-14 16:18:21 -0700119 Bitmap glowShape = srcDst.extractAlpha();
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800120
Winson Chung64a3cd42010-09-17 16:47:33 -0700121 // calculate the outer blur first
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800122 BlurMaskFilter outerBlurMaskFilter;
123 switch (thickness) {
124 case EXTRA_THICK:
125 outerBlurMaskFilter = sExtraThickOuterBlurMaskFilter;
126 break;
127 case THICK:
128 outerBlurMaskFilter = sThickOuterBlurMaskFilter;
129 break;
130 case MEDIUM:
131 outerBlurMaskFilter = sMediumOuterBlurMaskFilter;
132 break;
133 default:
134 throw new RuntimeException("Invalid blur thickness");
135 }
136 mBlurPaint.setMaskFilter(outerBlurMaskFilter);
Winson Chung64a3cd42010-09-17 16:47:33 -0700137 int[] outerBlurOffset = new int[2];
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800138 Bitmap thickOuterBlur = glowShape.extractAlpha(mBlurPaint, outerBlurOffset);
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800139 if (thickness == EXTRA_THICK) {
140 mBlurPaint.setMaskFilter(sMediumOuterBlurMaskFilter);
141 } else {
142 mBlurPaint.setMaskFilter(sThinOuterBlurMaskFilter);
143 }
144
145 int[] brightOutlineOffset = new int[2];
146 Bitmap brightOutline = glowShape.extractAlpha(mBlurPaint, brightOutlineOffset);
Winson Chung64a3cd42010-09-17 16:47:33 -0700147
148 // calculate the inner blur
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800149 srcDstCanvas.setBitmap(glowShape);
Winson Chung64a3cd42010-09-17 16:47:33 -0700150 srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT);
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800151 BlurMaskFilter innerBlurMaskFilter;
152 switch (thickness) {
153 case EXTRA_THICK:
154 innerBlurMaskFilter = sExtraThickInnerBlurMaskFilter;
155 break;
156 case THICK:
157 innerBlurMaskFilter = sThickInnerBlurMaskFilter;
158 break;
159 case MEDIUM:
160 innerBlurMaskFilter = sMediumInnerBlurMaskFilter;
161 break;
162 default:
163 throw new RuntimeException("Invalid blur thickness");
164 }
165 mBlurPaint.setMaskFilter(innerBlurMaskFilter);
Winson Chung64a3cd42010-09-17 16:47:33 -0700166 int[] thickInnerBlurOffset = new int[2];
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800167 Bitmap thickInnerBlur = glowShape.extractAlpha(mBlurPaint, thickInnerBlurOffset);
Winson Chung64a3cd42010-09-17 16:47:33 -0700168
169 // mask out the inner blur
170 srcDstCanvas.setBitmap(thickInnerBlur);
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800171 srcDstCanvas.drawBitmap(glowShape, -thickInnerBlurOffset[0],
Winson Chung64a3cd42010-09-17 16:47:33 -0700172 -thickInnerBlurOffset[1], mErasePaint);
173 srcDstCanvas.drawRect(0, 0, -thickInnerBlurOffset[0], thickInnerBlur.getHeight(),
174 mErasePaint);
175 srcDstCanvas.drawRect(0, 0, thickInnerBlur.getWidth(), -thickInnerBlurOffset[1],
176 mErasePaint);
177
178 // draw the inner and outer blur
179 srcDstCanvas.setBitmap(srcDst);
Michael Jurka2a9e7062011-01-14 15:48:04 -0800180 srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
Michael Jurka5f1c5092010-09-03 14:15:02 -0700181 mHolographicPaint.setColor(color);
Winson Chung64a3cd42010-09-17 16:47:33 -0700182 srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1],
183 mHolographicPaint);
184 srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1],
185 mHolographicPaint);
Michael Jurka5f1c5092010-09-03 14:15:02 -0700186
Winson Chung64a3cd42010-09-17 16:47:33 -0700187 // draw the bright outline
188 mHolographicPaint.setColor(outlineColor);
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800189 srcDstCanvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1],
Winson Chung64a3cd42010-09-17 16:47:33 -0700190 mHolographicPaint);
Michael Jurka5f1c5092010-09-03 14:15:02 -0700191
Winson Chung64a3cd42010-09-17 16:47:33 -0700192 // cleanup
Adam Cohenaaf473c2011-08-03 12:02:47 -0700193 srcDstCanvas.setBitmap(null);
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800194 brightOutline.recycle();
Winson Chung64a3cd42010-09-17 16:47:33 -0700195 thickOuterBlur.recycle();
196 thickInnerBlur.recycle();
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800197 glowShape.recycle();
Michael Jurka5f1c5092010-09-03 14:15:02 -0700198 }
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800199
Michael Jurka38b4f7c2010-12-14 16:46:39 -0800200 void applyExtraThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
201 int outlineColor) {
202 applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, EXTRA_THICK);
203 }
204
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800205 void applyThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
206 int outlineColor) {
207 applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, THICK);
208 }
209
210 void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
Michael Jurka8c3339b2012-06-14 16:18:21 -0700211 int outlineColor, boolean clipAlpha) {
212 applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, clipAlpha,
Peter Ng8db70002011-10-25 15:40:08 -0700213 MEDIUM);
214 }
215
216 void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
Adam Cohen5bb50bd2010-12-03 11:39:55 -0800217 int outlineColor) {
218 applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, MEDIUM);
219 }
220
Winson Chung7da10252010-10-28 16:07:04 -0700221}