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