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;
23508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyalimport android.graphics.Color;
245f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.Paint;
255f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.PorterDuff;
265f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.PorterDuffXfermode;
27508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyalimport android.graphics.Rect;
28508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyalimport android.graphics.Region.Op;
295f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
305f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkapublic class HolographicOutlineHelper {
31508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal
32508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal    private static final Rect sTempRect = new Rect();
33508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal
34508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal    private final Canvas mCanvas = new Canvas();
35508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal    private final Paint mDrawPaint = new Paint();
364be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private final Paint mBlurPaint = new Paint();
375f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    private final Paint mErasePaint = new Paint();
385f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
39508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal    private final BlurMaskFilter mMediumOuterBlurMaskFilter;
40508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal    private final BlurMaskFilter mThinOuterBlurMaskFilter;
41508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal    private final BlurMaskFilter mMediumInnerBlurMaskFilter;
424be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
43508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal    private final BlurMaskFilter mShaowBlurMaskFilter;
44508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal    private final int mShadowOffset;
455bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen
46508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal    /**
47508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal     * Padding used when creating shadow bitmap;
48508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal     */
49508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal    final int shadowBitmapPadding;
508e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy
51e572fe46f75adfb1adbf3c2a6812d1e3dbdee5e1Daniel Sandler    static HolographicOutlineHelper INSTANCE;
52e572fe46f75adfb1adbf3c2a6812d1e3dbdee5e1Daniel Sandler
53e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler    private HolographicOutlineHelper(Context context) {
54e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        final float scale = LauncherAppState.getInstance().getScreenDensity();
558e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy
56e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        mMediumOuterBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.OUTER);
57e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        mThinOuterBlurMaskFilter = new BlurMaskFilter(scale * 1.0f, BlurMaskFilter.Blur.OUTER);
58e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        mMediumInnerBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.NORMAL);
59e572fe46f75adfb1adbf3c2a6812d1e3dbdee5e1Daniel Sandler
60508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mShaowBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL);
61508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mShadowOffset = (int) (scale * 2.0f);
62508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        shadowBitmapPadding = (int) (scale * 4.0f);
63508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal
64508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mDrawPaint.setFilterBitmap(true);
65508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mDrawPaint.setAntiAlias(true);
664be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        mBlurPaint.setFilterBitmap(true);
674be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        mBlurPaint.setAntiAlias(true);
685f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
695f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        mErasePaint.setFilterBitmap(true);
705f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        mErasePaint.setAntiAlias(true);
715f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    }
725f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
73e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler    public static HolographicOutlineHelper obtain(Context context) {
74e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        if (INSTANCE == null) {
75e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler            INSTANCE = new HolographicOutlineHelper(context);
76e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        }
77e572fe46f75adfb1adbf3c2a6812d1e3dbdee5e1Daniel Sandler        return INSTANCE;
78e572fe46f75adfb1adbf3c2a6812d1e3dbdee5e1Daniel Sandler    }
79e572fe46f75adfb1adbf3c2a6812d1e3dbdee5e1Daniel Sandler
805f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    /**
8164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung     * Applies a more expensive and accurate outline to whatever is currently drawn in a specified
8264a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung     * bitmap.
835f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka     */
8464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung    void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
85508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal            int outlineColor) {
86508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true);
878db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng    }
888db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng    void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
89508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal            int outlineColor, boolean clipAlpha) {
905bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen
915bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        // We start by removing most of the alpha channel so as to ignore shadows, and
925bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        // other types of partial transparency when defining the shape of the object
938c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka        if (clipAlpha) {
948c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka            int[] srcBuffer = new int[srcDst.getWidth() * srcDst.getHeight()];
958c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka            srcDst.getPixels(srcBuffer,
968c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka                    0, srcDst.getWidth(), 0, 0, srcDst.getWidth(), srcDst.getHeight());
978c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka            for (int i = 0; i < srcBuffer.length; i++) {
988c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka                final int alpha = srcBuffer[i] >>> 24;
998c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka                if (alpha < 188) {
1008c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka                    srcBuffer[i] = 0;
1018c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka                }
1028c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka            }
1038c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka            srcDst.setPixels(srcBuffer,
1048c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka                    0, srcDst.getWidth(), 0, 0, srcDst.getWidth(), srcDst.getHeight());
1058db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng        }
1068c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka        Bitmap glowShape = srcDst.extractAlpha();
1075bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen
10864a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // calculate the outer blur first
109508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mBlurPaint.setMaskFilter(mMediumOuterBlurMaskFilter);
11064a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        int[] outerBlurOffset = new int[2];
1115bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        Bitmap thickOuterBlur = glowShape.extractAlpha(mBlurPaint, outerBlurOffset);
11238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka
113508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mBlurPaint.setMaskFilter(mThinOuterBlurMaskFilter);
11438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        int[] brightOutlineOffset = new int[2];
11538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        Bitmap brightOutline = glowShape.extractAlpha(mBlurPaint, brightOutlineOffset);
1165f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
11764a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // calculate the inner blur
1185bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        srcDstCanvas.setBitmap(glowShape);
11964a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT);
120508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mBlurPaint.setMaskFilter(mMediumInnerBlurMaskFilter);
12164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        int[] thickInnerBlurOffset = new int[2];
1225bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        Bitmap thickInnerBlur = glowShape.extractAlpha(mBlurPaint, thickInnerBlurOffset);
1235f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
12464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // mask out the inner blur
12564a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.setBitmap(thickInnerBlur);
1265bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        srcDstCanvas.drawBitmap(glowShape, -thickInnerBlurOffset[0],
12764a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung                -thickInnerBlurOffset[1], mErasePaint);
12864a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawRect(0, 0, -thickInnerBlurOffset[0], thickInnerBlur.getHeight(),
12964a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung                mErasePaint);
13064a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawRect(0, 0, thickInnerBlur.getWidth(), -thickInnerBlurOffset[1],
13164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung                mErasePaint);
1325f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
13364a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // draw the inner and outer blur
13464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.setBitmap(srcDst);
1352a9e70655f5885549acfdb6e770d2516bc8c87e3Michael Jurka        srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
136508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mDrawPaint.setColor(color);
13764a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1],
138508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                mDrawPaint);
13964a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1],
140508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                mDrawPaint);
14164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung
14264a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // draw the bright outline
143508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mDrawPaint.setColor(outlineColor);
14438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        srcDstCanvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1],
145508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                mDrawPaint);
14664a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung
14764a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // cleanup
148aaf473c2bb6329b3b09ed2e19de6aae26077050cAdam Cohen        srcDstCanvas.setBitmap(null);
14938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka        brightOutline.recycle();
15064a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        thickOuterBlur.recycle();
15164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        thickInnerBlur.recycle();
1525bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen        glowShape.recycle();
1535f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    }
1545bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen
155508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal    Bitmap createMediumDropShadow(BubbleTextView view) {
156508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        final Bitmap result = Bitmap.createBitmap(
157508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                view.getWidth() + shadowBitmapPadding + shadowBitmapPadding,
158508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                view.getHeight() + shadowBitmapPadding + shadowBitmapPadding + mShadowOffset,
159508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                Bitmap.Config.ARGB_8888);
160508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal
161508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mCanvas.setBitmap(result);
162508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal
163508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        final Rect clipRect = sTempRect;
164508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        view.getDrawingRect(sTempRect);
165508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        // adjust the clip rect so that we don't include the text label
166508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        clipRect.bottom = view.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V
167508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                + view.getLayout().getLineTop(0);
168508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal
169508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        // Draw the View into the bitmap.
170508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        // The translate of scrollX and scrollY is necessary when drawing TextViews, because
171508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        // they set scrollX and scrollY to large values to achieve centered text
172508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mCanvas.save();
173508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mCanvas.scale(view.getScaleX(), view.getScaleY(),
174508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                view.getWidth() / 2 + shadowBitmapPadding,
175508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                view.getHeight() / 2 + shadowBitmapPadding);
176508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mCanvas.translate(-view.getScrollX() + shadowBitmapPadding,
177508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                -view.getScrollY() + shadowBitmapPadding);
178508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mCanvas.clipRect(clipRect, Op.REPLACE);
179508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        view.draw(mCanvas);
180508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mCanvas.restore();
181508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal
182508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        int[] blurOffst = new int[2];
183508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mBlurPaint.setMaskFilter(mShaowBlurMaskFilter);
184508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        Bitmap blurBitmap = result.extractAlpha(mBlurPaint, blurOffst);
185508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal
186508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mCanvas.save();
187508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
188508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mCanvas.translate(blurOffst[0], blurOffst[1]);
189508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal
190508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mDrawPaint.setColor(Color.BLACK);
191508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mDrawPaint.setAlpha(30);
192508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mCanvas.drawBitmap(blurBitmap, 0, 0, mDrawPaint);
193508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal
194508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mDrawPaint.setAlpha(60);
195508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mCanvas.drawBitmap(blurBitmap, 0, mShadowOffset, mDrawPaint);
196508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mCanvas.restore();
197508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal
198508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        mCanvas.setBitmap(null);
199508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        blurBitmap.recycle();
200508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal
201508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        return result;
2025bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen    }
2037da1025bd7f15b04cf55c79b73e94e5e1bc959d9Winson Chung}
204