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
175f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkapackage com.android.launcher2;
185f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
195f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.Bitmap;
205f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.BlurMaskFilter;
215f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.Canvas;
225f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.Paint;
235f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.PorterDuff;
245f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.PorterDuffXfermode;
255f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
265f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkapublic class HolographicOutlineHelper {
275f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    private final Paint mHolographicPaint = new Paint();
284be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private final Paint mBlurPaint = new Paint();
295f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    private final Paint mErasePaint = new Paint();
305f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
3138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka    public static final int MAX_OUTER_BLUR_RADIUS;
321908d07151e0d3f82899f368874e41ed1e49ba16Winson Chung    public static final int MIN_OUTER_BLUR_RADIUS;
334be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
3438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka    private static final BlurMaskFilter sExtraThickOuterBlurMaskFilter;
358e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy    private static final BlurMaskFilter sThickOuterBlurMaskFilter;
368e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy    private static final BlurMaskFilter sMediumOuterBlurMaskFilter;
378e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy    private static final BlurMaskFilter sThinOuterBlurMaskFilter;
388e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy    private static final BlurMaskFilter sThickInnerBlurMaskFilter;
3938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka    private static final BlurMaskFilter sExtraThickInnerBlurMaskFilter;
405bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen    private static final BlurMaskFilter sMediumInnerBlurMaskFilter;
415bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen
425bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen    private static final int THICK = 0;
435bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen    private static final int MEDIUM = 1;
4438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka    private static final int EXTRA_THICK = 2;
458e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy
468e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy    static {
478e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        final float scale = LauncherApplication.getScreenDensity();
488e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy
491908d07151e0d3f82899f368874e41ed1e49ba16Winson Chung        MIN_OUTER_BLUR_RADIUS = (int) (scale * 1.0f);
5038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        MAX_OUTER_BLUR_RADIUS = (int) (scale * 12.0f);
518e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy
5238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        sExtraThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 12.0f, BlurMaskFilter.Blur.OUTER);
5338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        sThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.OUTER);
548e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        sMediumOuterBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.OUTER);
558e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        sThinOuterBlurMaskFilter = new BlurMaskFilter(scale * 1.0f, BlurMaskFilter.Blur.OUTER);
5638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        sExtraThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.NORMAL);
578e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        sThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL);
585bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        sMediumInnerBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.NORMAL);
598e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy    }
604be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
6164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung    HolographicOutlineHelper() {
625f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        mHolographicPaint.setFilterBitmap(true);
635f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        mHolographicPaint.setAntiAlias(true);
644be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        mBlurPaint.setFilterBitmap(true);
654be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        mBlurPaint.setAntiAlias(true);
665f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
675f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        mErasePaint.setFilterBitmap(true);
685f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        mErasePaint.setAntiAlias(true);
695f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    }
705f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
715f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    /**
725f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka     * Returns the interpolated holographic highlight alpha for the effect we want when scrolling
735f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka     * pages.
745f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka     */
75b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    public static float highlightAlphaInterpolator(float r) {
76b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        float maxAlpha = 0.6f;
77e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung        return (float) Math.pow(maxAlpha * (1.0f - r), 1.5f);
785f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    }
795f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
805f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    /**
815f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka     * Returns the interpolated view alpha for the effect we want when scrolling pages.
825f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka     */
83b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    public static float viewAlphaInterpolator(float r) {
84e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung        final float pivot = 0.95f;
855f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        if (r < pivot) {
86e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung            return (float) Math.pow(r / pivot, 1.5f);
875f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        } else {
885f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka            return 1.0f;
895f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        }
905f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    }
915f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
928e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy    /**
9364a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung     * Applies a more expensive and accurate outline to whatever is currently drawn in a specified
9464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung     * bitmap.
955f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka     */
9664a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung    void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
975bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen            int outlineColor, int thickness) {
988c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka        applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true,
998db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng                thickness);
1008db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng    }
1018db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng    void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
1028c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka            int outlineColor, boolean clipAlpha, int thickness) {
1035bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen
1045bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        // We start by removing most of the alpha channel so as to ignore shadows, and
1055bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        // other types of partial transparency when defining the shape of the object
1068c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka        if (clipAlpha) {
1078c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka            int[] srcBuffer = new int[srcDst.getWidth() * srcDst.getHeight()];
1088c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka            srcDst.getPixels(srcBuffer,
1098c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka                    0, srcDst.getWidth(), 0, 0, srcDst.getWidth(), srcDst.getHeight());
1108c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka            for (int i = 0; i < srcBuffer.length; i++) {
1118c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka                final int alpha = srcBuffer[i] >>> 24;
1128c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka                if (alpha < 188) {
1138c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka                    srcBuffer[i] = 0;
1148c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka                }
1158c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka            }
1168c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka            srcDst.setPixels(srcBuffer,
1178c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka                    0, srcDst.getWidth(), 0, 0, srcDst.getWidth(), srcDst.getHeight());
1188db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng        }
1198c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka        Bitmap glowShape = srcDst.extractAlpha();
1205bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen
12164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // calculate the outer blur first
12238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        BlurMaskFilter outerBlurMaskFilter;
12338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        switch (thickness) {
12438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka            case EXTRA_THICK:
12538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka                outerBlurMaskFilter = sExtraThickOuterBlurMaskFilter;
12638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka                break;
12738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka            case THICK:
12838b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka                outerBlurMaskFilter = sThickOuterBlurMaskFilter;
12938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka                break;
13038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka            case MEDIUM:
13138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka                outerBlurMaskFilter = sMediumOuterBlurMaskFilter;
13238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka                break;
13338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka            default:
13438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka                throw new RuntimeException("Invalid blur thickness");
13538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        }
13638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        mBlurPaint.setMaskFilter(outerBlurMaskFilter);
13764a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        int[] outerBlurOffset = new int[2];
1385bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        Bitmap thickOuterBlur = glowShape.extractAlpha(mBlurPaint, outerBlurOffset);
13938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        if (thickness == EXTRA_THICK) {
14038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka            mBlurPaint.setMaskFilter(sMediumOuterBlurMaskFilter);
14138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        } else {
14238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka            mBlurPaint.setMaskFilter(sThinOuterBlurMaskFilter);
14338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        }
14438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka
14538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        int[] brightOutlineOffset = new int[2];
14638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        Bitmap brightOutline = glowShape.extractAlpha(mBlurPaint, brightOutlineOffset);
1475f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
14864a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // calculate the inner blur
1495bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        srcDstCanvas.setBitmap(glowShape);
15064a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT);
15138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        BlurMaskFilter innerBlurMaskFilter;
15238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        switch (thickness) {
15338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka            case EXTRA_THICK:
15438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka                innerBlurMaskFilter = sExtraThickInnerBlurMaskFilter;
15538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka                break;
15638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka            case THICK:
15738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka                innerBlurMaskFilter = sThickInnerBlurMaskFilter;
15838b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka                break;
15938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka            case MEDIUM:
16038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka                innerBlurMaskFilter = sMediumInnerBlurMaskFilter;
16138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka                break;
16238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka            default:
16338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka                throw new RuntimeException("Invalid blur thickness");
16438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        }
16538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        mBlurPaint.setMaskFilter(innerBlurMaskFilter);
16664a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        int[] thickInnerBlurOffset = new int[2];
1675bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        Bitmap thickInnerBlur = glowShape.extractAlpha(mBlurPaint, thickInnerBlurOffset);
1685f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
16964a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // mask out the inner blur
17064a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.setBitmap(thickInnerBlur);
1715bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        srcDstCanvas.drawBitmap(glowShape, -thickInnerBlurOffset[0],
17264a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung                -thickInnerBlurOffset[1], mErasePaint);
17364a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawRect(0, 0, -thickInnerBlurOffset[0], thickInnerBlur.getHeight(),
17464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung                mErasePaint);
17564a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawRect(0, 0, thickInnerBlur.getWidth(), -thickInnerBlurOffset[1],
17664a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung                mErasePaint);
1775f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
17864a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // draw the inner and outer blur
17964a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.setBitmap(srcDst);
1802a9e70655f5885549acfdb6e770d2516bc8c87e3Michael Jurka        srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
18164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        mHolographicPaint.setColor(color);
18264a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1],
18364a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung                mHolographicPaint);
18464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1],
18564a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung                mHolographicPaint);
18664a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung
18764a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // draw the bright outline
18864a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        mHolographicPaint.setColor(outlineColor);
18938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        srcDstCanvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1],
19064a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung                mHolographicPaint);
19164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung
19264a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // cleanup
193aaf473c2bb6329b3b09ed2e19de6aae26077050cAdam Cohen        srcDstCanvas.setBitmap(null);
19438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        brightOutline.recycle();
19564a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        thickOuterBlur.recycle();
19664a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        thickInnerBlur.recycle();
1975bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        glowShape.recycle();
1985f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    }
1995bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen
20038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka    void applyExtraThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
20138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka            int outlineColor) {
20238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, EXTRA_THICK);
20338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka    }
20438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka
2055bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen    void applyThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
2065bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen            int outlineColor) {
2075bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, THICK);
2085bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen    }
2095bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen
2105bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen    void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
2118c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka            int outlineColor, boolean clipAlpha) {
2128c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka        applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, clipAlpha,
2138db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng                MEDIUM);
2148db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng    }
2158db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng
2168db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng    void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
2175bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen            int outlineColor) {
2185bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, MEDIUM);
2195bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen    }
2205bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen
2217da1025bd7f15b04cf55c79b73e94e5e1bc959d9Winson Chung}
222