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