1ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei/* 2ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Copyright (C) 2014 The Android Open Source Project 3ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * 4ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Licensed under the Apache License, Version 2.0 (the "License"); 5ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * you may not use this file except in compliance with the License. 6ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * You may obtain a copy of the License at 7ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * 8ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * http://www.apache.org/licenses/LICENSE-2.0 9ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * 10ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Unless required by applicable law or agreed to in writing, software 11ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * distributed under the License is distributed on an "AS IS" BASIS, 12ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * See the License for the specific language governing permissions and 14ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * limitations under the License. 15ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 16ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 17ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weipackage com.android.bitmap.drawable; 18ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 19ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.content.res.Resources; 20ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.Bitmap; 21ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.BitmapShader; 22ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.Canvas; 23ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.Color; 24ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.ColorFilter; 25ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.Matrix; 26ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.Paint; 27ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.Paint.Style; 28ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.Rect; 29ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.Shader.TileMode; 3009f46006437e7de33afdb51192bf0bdc08e97040Mark Weiimport android.graphics.drawable.BitmapDrawable; 31ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 32ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport com.android.bitmap.BitmapCache; 33ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 34ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei/** 35ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Custom BasicBitmapDrawable implementation for circular images. 36ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * 37ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * This draws all bitmaps as a circle with an optional border stroke. 38ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 3909f46006437e7de33afdb51192bf0bdc08e97040Mark Weipublic class CircularBitmapDrawable extends ExtendedBitmapDrawable { 40ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private final Paint mBitmapPaint = new Paint(); 41ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private final Paint mBorderPaint = new Paint(); 42a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev private final Rect mRect = new Rect(); 43a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev private final Matrix mMatrix = new Matrix(); 44ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 45ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private float mBorderWidth; 46df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei private Bitmap mShaderBitmap; 47ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 48ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public CircularBitmapDrawable(Resources res, 49ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei BitmapCache cache, boolean limitDensity) { 5009f46006437e7de33afdb51192bf0bdc08e97040Mark Wei this(res, cache, limitDensity, null); 5109f46006437e7de33afdb51192bf0bdc08e97040Mark Wei } 5209f46006437e7de33afdb51192bf0bdc08e97040Mark Wei 5309f46006437e7de33afdb51192bf0bdc08e97040Mark Wei public CircularBitmapDrawable(Resources res, 5409f46006437e7de33afdb51192bf0bdc08e97040Mark Wei BitmapCache cache, boolean limitDensity, ExtendedOptions opts) { 5509f46006437e7de33afdb51192bf0bdc08e97040Mark Wei super(res, cache, limitDensity, opts); 56ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 57ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBitmapPaint.setAntiAlias(true); 58ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBitmapPaint.setFilterBitmap(true); 59ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBitmapPaint.setDither(true); 60ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 61ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setColor(Color.TRANSPARENT); 62ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setStyle(Style.STROKE); 63ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setStrokeWidth(mBorderWidth); 64ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setAntiAlias(true); 65ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 66ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 67ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei /** 68ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Set the border stroke width of this drawable. 69ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 70ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void setBorderWidth(final float borderWidth) { 71ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei final boolean changed = mBorderPaint.getStrokeWidth() != borderWidth; 72ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setStrokeWidth(borderWidth); 73ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderWidth = borderWidth; 74ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 75ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (changed) { 76ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei invalidateSelf(); 77ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 78ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 79ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 80ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei /** 81ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Set the border stroke color of this drawable. Set to {@link Color#TRANSPARENT} to disable. 82ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 83ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void setBorderColor(final int color) { 84ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei final boolean changed = mBorderPaint.getColor() != color; 85ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setColor(color); 86ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 87ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (changed) { 88ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei invalidateSelf(); 89ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 90ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 91ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 92ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei @Override 93ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei protected void onDrawBitmap(final Canvas canvas, final Rect src, 94ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei final Rect dst) { 9509f46006437e7de33afdb51192bf0bdc08e97040Mark Wei onDrawCircularBitmap(getBitmap().bmp, canvas, src, dst, 1f); 9609f46006437e7de33afdb51192bf0bdc08e97040Mark Wei } 9709f46006437e7de33afdb51192bf0bdc08e97040Mark Wei 9809f46006437e7de33afdb51192bf0bdc08e97040Mark Wei @Override 9909f46006437e7de33afdb51192bf0bdc08e97040Mark Wei protected void onDrawPlaceholderOrProgress(final Canvas canvas, 10009f46006437e7de33afdb51192bf0bdc08e97040Mark Wei final TileDrawable drawable) { 101c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei Rect bounds = getBounds(); 102c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei if (drawable.getInnerDrawable() instanceof BitmapDrawable) { 103c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei BitmapDrawable placeholder = 104c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei (BitmapDrawable) drawable.getInnerDrawable(); 105c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei Bitmap bitmap = placeholder.getBitmap(); 106c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei float alpha = placeholder.getPaint().getAlpha() / 255f; 107a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev mRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight()); 108a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev onDrawCircularBitmap(bitmap, canvas, mRect, bounds, alpha); 109c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei } else { 110c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei super.onDrawPlaceholderOrProgress(canvas, drawable); 111c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei } 112c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei 113c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei // Then draw the border. 114c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei canvas.drawCircle(bounds.centerX(), bounds.centerY(), 115c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei bounds.width() / 2f - mBorderWidth / 2, mBorderPaint); 116ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 117ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 118ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei /** 119ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Call this method with a given bitmap to draw it onto the given canvas, masked by a circular 120ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * BitmapShader. 121ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 122ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei protected void onDrawCircularBitmap(final Bitmap bitmap, final Canvas canvas, 1238dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei final Rect src, final Rect dst) { 1248dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei onDrawCircularBitmap(bitmap, canvas, src, dst, 1f); 1258dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei } 1268dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei 1278dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei /** 1288dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei * Call this method with a given bitmap to draw it onto the given canvas, masked by a circular 1298dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei * BitmapShader. The alpha parameter is the value from 0f to 1f to attenuate the alpha by. 1308dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei */ 1318dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei protected void onDrawCircularBitmap(final Bitmap bitmap, final Canvas canvas, 13209f46006437e7de33afdb51192bf0bdc08e97040Mark Wei final Rect src, final Rect dst, final float alpha) { 133ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Draw bitmap through shader first. 134df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei BitmapShader shader = (BitmapShader) mBitmapPaint.getShader(); 135df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei if (shader == null || mShaderBitmap != bitmap) { 136df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei shader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP); 137df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mShaderBitmap = bitmap; 138df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 139ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 140a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev mMatrix.reset(); 141ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Fit bitmap to bounds. 142ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei float scale = Math.max((float) dst.width() / src.width(), 143ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei (float) dst.height() / src.height()); 144a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev mMatrix.postScale(scale, scale); 145ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Translate bitmap to dst bounds. 146a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev mMatrix.postTranslate(dst.left, dst.top); 147a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev shader.setLocalMatrix(mMatrix); 1485c102db5a1a16a2adcc7728693a6e65a981f91aeLeon Scroggins III mBitmapPaint.setShader(shader); 149df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei 15009f46006437e7de33afdb51192bf0bdc08e97040Mark Wei int oldAlpha = mBitmapPaint.getAlpha(); 15109f46006437e7de33afdb51192bf0bdc08e97040Mark Wei mBitmapPaint.setAlpha((int) (oldAlpha * alpha)); 152ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei canvas.drawCircle(dst.centerX(), dst.centerY(), dst.width() / 2, 153ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBitmapPaint); 15409f46006437e7de33afdb51192bf0bdc08e97040Mark Wei mBitmapPaint.setAlpha(oldAlpha); 155ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 156ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Then draw the border. 157ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei canvas.drawCircle(dst.centerX(), dst.centerY(), 158ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei dst.width() / 2f - mBorderWidth / 2, mBorderPaint); 159ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 160ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 161ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei @Override 162ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void setAlpha(int alpha) { 163ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei super.setAlpha(alpha); 164ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 165ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei final int old = mBitmapPaint.getAlpha(); 166ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBitmapPaint.setAlpha(alpha); 167ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (alpha != old) { 168ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei invalidateSelf(); 169ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 170ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 171ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 172ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei @Override 173ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void setColorFilter(ColorFilter cf) { 174ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei super.setColorFilter(cf); 175ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mPaint.setColorFilter(cf); 176ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 177ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei} 178