15f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka/* 25f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * Copyright (C) 2008 The Android Open Source Project 35f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * 45f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * Licensed under the Apache License, Version 2.0 (the "License"); 55f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * you may not use this file except in compliance with the License. 65f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * You may obtain a copy of the License at 75f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * 85f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * http://www.apache.org/licenses/LICENSE-2.0 95f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * 105f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * Unless required by applicable law or agreed to in writing, software 115f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * distributed under the License is distributed on an "AS IS" BASIS, 125f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * See the License for the specific language governing permissions and 145f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * limitations under the License. 155f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka */ 165f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 17325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3; 185f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 19e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandlerimport android.content.Context; 205f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.Bitmap; 215f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.BlurMaskFilter; 225f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.Canvas; 235f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.Paint; 245f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.PorterDuff; 255f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.PorterDuffXfermode; 265f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 275f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkapublic class HolographicOutlineHelper { 285f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka private final Paint mHolographicPaint = new Paint(); 294be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private final Paint mBlurPaint = new Paint(); 305f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka private final Paint mErasePaint = new Paint(); 315f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 32e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler public int mMaxOuterBlurRadius; 33e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler public int mMinOuterBlurRadius; 344be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 35e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler private BlurMaskFilter mExtraThickOuterBlurMaskFilter; 36e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler private BlurMaskFilter mThickOuterBlurMaskFilter; 37e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler private BlurMaskFilter mMediumOuterBlurMaskFilter; 38e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler private BlurMaskFilter mThinOuterBlurMaskFilter; 39e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler private BlurMaskFilter mThickInnerBlurMaskFilter; 40e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler private BlurMaskFilter mExtraThickInnerBlurMaskFilter; 41e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler private BlurMaskFilter mMediumInnerBlurMaskFilter; 425bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen 435bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen private static final int THICK = 0; 445bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen private static final int MEDIUM = 1; 4538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka private static final int EXTRA_THICK = 2; 468e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy 47e572fe46f75adfb1adbf3c2a6812d1e3dbdee5e1Daniel Sandler static HolographicOutlineHelper INSTANCE; 48e572fe46f75adfb1adbf3c2a6812d1e3dbdee5e1Daniel Sandler 49e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler private HolographicOutlineHelper(Context context) { 50e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler final float scale = LauncherAppState.getInstance().getScreenDensity(); 518e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy 52e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler mMinOuterBlurRadius = (int) (scale * 1.0f); 53e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler mMaxOuterBlurRadius = (int) (scale * 12.0f); 548e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy 55e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler mExtraThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 12.0f, BlurMaskFilter.Blur.OUTER); 56e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler mThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.OUTER); 57e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler mMediumOuterBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.OUTER); 58e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler mThinOuterBlurMaskFilter = new BlurMaskFilter(scale * 1.0f, BlurMaskFilter.Blur.OUTER); 59e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler mExtraThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.NORMAL); 60e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler mThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL); 61e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler mMediumInnerBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.NORMAL); 62e572fe46f75adfb1adbf3c2a6812d1e3dbdee5e1Daniel Sandler 635f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka mHolographicPaint.setFilterBitmap(true); 645f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka mHolographicPaint.setAntiAlias(true); 654be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mBlurPaint.setFilterBitmap(true); 664be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mBlurPaint.setAntiAlias(true); 675f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 685f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka mErasePaint.setFilterBitmap(true); 695f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka mErasePaint.setAntiAlias(true); 705f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka } 715f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 72e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler public static HolographicOutlineHelper obtain(Context context) { 73e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler if (INSTANCE == null) { 74e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler INSTANCE = new HolographicOutlineHelper(context); 75e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler } 76e572fe46f75adfb1adbf3c2a6812d1e3dbdee5e1Daniel Sandler return INSTANCE; 77e572fe46f75adfb1adbf3c2a6812d1e3dbdee5e1Daniel Sandler } 78e572fe46f75adfb1adbf3c2a6812d1e3dbdee5e1Daniel Sandler 795f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka /** 805f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * Returns the interpolated holographic highlight alpha for the effect we want when scrolling 815f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * pages. 825f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka */ 83b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung public static float highlightAlphaInterpolator(float r) { 84b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung float maxAlpha = 0.6f; 85e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung return (float) Math.pow(maxAlpha * (1.0f - r), 1.5f); 865f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka } 875f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 885f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka /** 895f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * Returns the interpolated view alpha for the effect we want when scrolling pages. 905f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka */ 91b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung public static float viewAlphaInterpolator(float r) { 92e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung final float pivot = 0.95f; 935f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka if (r < pivot) { 94e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung return (float) Math.pow(r / pivot, 1.5f); 955f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka } else { 965f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka return 1.0f; 975f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka } 985f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka } 995f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 1008e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy /** 10164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung * Applies a more expensive and accurate outline to whatever is currently drawn in a specified 10264a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung * bitmap. 1035f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka */ 10464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, 1055bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen int outlineColor, int thickness) { 1068c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true, 1078db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng thickness); 1088db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng } 1098db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, 1108c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka int outlineColor, boolean clipAlpha, int thickness) { 1115bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen 1125bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen // We start by removing most of the alpha channel so as to ignore shadows, and 1135bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen // other types of partial transparency when defining the shape of the object 1148c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka if (clipAlpha) { 1158c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka int[] srcBuffer = new int[srcDst.getWidth() * srcDst.getHeight()]; 1168c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka srcDst.getPixels(srcBuffer, 1178c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka 0, srcDst.getWidth(), 0, 0, srcDst.getWidth(), srcDst.getHeight()); 1188c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka for (int i = 0; i < srcBuffer.length; i++) { 1198c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka final int alpha = srcBuffer[i] >>> 24; 1208c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka if (alpha < 188) { 1218c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka srcBuffer[i] = 0; 1228c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka } 1238c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka } 1248c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka srcDst.setPixels(srcBuffer, 1258c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka 0, srcDst.getWidth(), 0, 0, srcDst.getWidth(), srcDst.getHeight()); 1268db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng } 1278c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka Bitmap glowShape = srcDst.extractAlpha(); 1285bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen 12964a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung // calculate the outer blur first 13038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka BlurMaskFilter outerBlurMaskFilter; 13138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka switch (thickness) { 13238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka case EXTRA_THICK: 133e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler outerBlurMaskFilter = mExtraThickOuterBlurMaskFilter; 13438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka break; 13538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka case THICK: 136e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler outerBlurMaskFilter = mThickOuterBlurMaskFilter; 13738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka break; 13838b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka case MEDIUM: 139e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler outerBlurMaskFilter = mMediumOuterBlurMaskFilter; 14038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka break; 14138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka default: 14238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka throw new RuntimeException("Invalid blur thickness"); 14338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } 14438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka mBlurPaint.setMaskFilter(outerBlurMaskFilter); 14564a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung int[] outerBlurOffset = new int[2]; 1465bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen Bitmap thickOuterBlur = glowShape.extractAlpha(mBlurPaint, outerBlurOffset); 14738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka if (thickness == EXTRA_THICK) { 148e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler mBlurPaint.setMaskFilter(mMediumOuterBlurMaskFilter); 14938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } else { 150e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler mBlurPaint.setMaskFilter(mThinOuterBlurMaskFilter); 15138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } 15238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka 15338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka int[] brightOutlineOffset = new int[2]; 15438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka Bitmap brightOutline = glowShape.extractAlpha(mBlurPaint, brightOutlineOffset); 1555f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 15664a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung // calculate the inner blur 1575bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen srcDstCanvas.setBitmap(glowShape); 15864a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT); 15938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka BlurMaskFilter innerBlurMaskFilter; 16038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka switch (thickness) { 16138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka case EXTRA_THICK: 162e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler innerBlurMaskFilter = mExtraThickInnerBlurMaskFilter; 16338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka break; 16438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka case THICK: 165e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler innerBlurMaskFilter = mThickInnerBlurMaskFilter; 16638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka break; 16738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka case MEDIUM: 168e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler innerBlurMaskFilter = mMediumInnerBlurMaskFilter; 16938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka break; 17038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka default: 17138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka throw new RuntimeException("Invalid blur thickness"); 17238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } 17338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka mBlurPaint.setMaskFilter(innerBlurMaskFilter); 17464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung int[] thickInnerBlurOffset = new int[2]; 1755bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen Bitmap thickInnerBlur = glowShape.extractAlpha(mBlurPaint, thickInnerBlurOffset); 1765f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 17764a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung // mask out the inner blur 17864a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung srcDstCanvas.setBitmap(thickInnerBlur); 1795bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen srcDstCanvas.drawBitmap(glowShape, -thickInnerBlurOffset[0], 18064a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung -thickInnerBlurOffset[1], mErasePaint); 18164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung srcDstCanvas.drawRect(0, 0, -thickInnerBlurOffset[0], thickInnerBlur.getHeight(), 18264a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung mErasePaint); 18364a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung srcDstCanvas.drawRect(0, 0, thickInnerBlur.getWidth(), -thickInnerBlurOffset[1], 18464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung mErasePaint); 1855f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 18664a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung // draw the inner and outer blur 18764a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung srcDstCanvas.setBitmap(srcDst); 1882a9e70655f5885549acfdb6e770d2516bc8c87e3Michael Jurka srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR); 18964a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung mHolographicPaint.setColor(color); 19064a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1], 19164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung mHolographicPaint); 19264a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1], 19364a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung mHolographicPaint); 19464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung 19564a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung // draw the bright outline 19664a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung mHolographicPaint.setColor(outlineColor); 19738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka srcDstCanvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1], 19864a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung mHolographicPaint); 19964a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung 20064a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung // cleanup 201aaf473c2bb6329b3b09ed2e19de6aae26077050cAdam Cohen srcDstCanvas.setBitmap(null); 20238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka brightOutline.recycle(); 20364a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung thickOuterBlur.recycle(); 20464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung thickInnerBlur.recycle(); 2055bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen glowShape.recycle(); 2065f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka } 2075bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen 20838b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka void applyExtraThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, 20938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka int outlineColor) { 21038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, EXTRA_THICK); 21138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } 21238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka 2135bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen void applyThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, 2145bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen int outlineColor) { 2155bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, THICK); 2165bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen } 2175bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen 2185bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, 2198c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka int outlineColor, boolean clipAlpha) { 2208c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, clipAlpha, 2218db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng MEDIUM); 2228db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng } 2238db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng 2248db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, 2255bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen int outlineColor) { 2265bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, MEDIUM); 2275bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen } 2285bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen 2297da1025bd7f15b04cf55c79b73e94e5e1bc959d9Winson Chung} 230