| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.bitmap.drawable; |
| |
| import android.content.res.Resources; |
| import android.graphics.Bitmap; |
| import android.graphics.BitmapShader; |
| import android.graphics.Canvas; |
| import android.graphics.Color; |
| import android.graphics.ColorFilter; |
| import android.graphics.Matrix; |
| import android.graphics.Paint; |
| import android.graphics.Paint.Style; |
| import android.graphics.Rect; |
| import android.graphics.Shader.TileMode; |
| import android.graphics.drawable.BitmapDrawable; |
| |
| import com.android.bitmap.BitmapCache; |
| |
| /** |
| * Custom BasicBitmapDrawable implementation for circular images. |
| * |
| * This draws all bitmaps as a circle with an optional border stroke. |
| */ |
| public class CircularBitmapDrawable extends ExtendedBitmapDrawable { |
| private static Matrix sMatrix = new Matrix(); |
| |
| private final Paint mBitmapPaint = new Paint(); |
| private final Paint mBorderPaint = new Paint(); |
| |
| private float mBorderWidth; |
| private Bitmap mShaderBitmap; |
| |
| public CircularBitmapDrawable(Resources res, |
| BitmapCache cache, boolean limitDensity) { |
| this(res, cache, limitDensity, null); |
| } |
| |
| public CircularBitmapDrawable(Resources res, |
| BitmapCache cache, boolean limitDensity, ExtendedOptions opts) { |
| super(res, cache, limitDensity, opts); |
| |
| mBitmapPaint.setAntiAlias(true); |
| mBitmapPaint.setFilterBitmap(true); |
| mBitmapPaint.setDither(true); |
| |
| mBorderPaint.setColor(Color.TRANSPARENT); |
| mBorderPaint.setStyle(Style.STROKE); |
| mBorderPaint.setStrokeWidth(mBorderWidth); |
| mBorderPaint.setAntiAlias(true); |
| } |
| |
| /** |
| * Set the border stroke width of this drawable. |
| */ |
| public void setBorderWidth(final float borderWidth) { |
| final boolean changed = mBorderPaint.getStrokeWidth() != borderWidth; |
| mBorderPaint.setStrokeWidth(borderWidth); |
| mBorderWidth = borderWidth; |
| |
| if (changed) { |
| invalidateSelf(); |
| } |
| } |
| |
| /** |
| * Set the border stroke color of this drawable. Set to {@link Color#TRANSPARENT} to disable. |
| */ |
| public void setBorderColor(final int color) { |
| final boolean changed = mBorderPaint.getColor() != color; |
| mBorderPaint.setColor(color); |
| |
| if (changed) { |
| invalidateSelf(); |
| } |
| } |
| |
| @Override |
| protected void onDrawBitmap(final Canvas canvas, final Rect src, |
| final Rect dst) { |
| onDrawCircularBitmap(getBitmap().bmp, canvas, src, dst, 1f); |
| } |
| |
| @Override |
| protected void onDrawPlaceholderOrProgress(final Canvas canvas, |
| final TileDrawable drawable) { |
| BitmapDrawable placeholder = (BitmapDrawable) drawable.getInnerDrawable(); |
| Bitmap bitmap = placeholder.getBitmap(); |
| float alpha = placeholder.getPaint().getAlpha() / 255f; |
| sRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight()); |
| onDrawCircularBitmap(bitmap, canvas, sRect, getBounds(), alpha); |
| } |
| |
| /** |
| * Call this method with a given bitmap to draw it onto the given canvas, masked by a circular |
| * BitmapShader. |
| */ |
| protected void onDrawCircularBitmap(final Bitmap bitmap, final Canvas canvas, |
| final Rect src, final Rect dst) { |
| onDrawCircularBitmap(bitmap, canvas, src, dst, 1f); |
| } |
| |
| /** |
| * Call this method with a given bitmap to draw it onto the given canvas, masked by a circular |
| * BitmapShader. The alpha parameter is the value from 0f to 1f to attenuate the alpha by. |
| */ |
| protected void onDrawCircularBitmap(final Bitmap bitmap, final Canvas canvas, |
| final Rect src, final Rect dst, final float alpha) { |
| // Draw bitmap through shader first. |
| BitmapShader shader = (BitmapShader) mBitmapPaint.getShader(); |
| if (shader == null || mShaderBitmap != bitmap) { |
| shader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP); |
| mShaderBitmap = bitmap; |
| } |
| |
| sMatrix.reset(); |
| // Fit bitmap to bounds. |
| float scale = Math.max((float) dst.width() / src.width(), |
| (float) dst.height() / src.height()); |
| sMatrix.postScale(scale, scale); |
| // Translate bitmap to dst bounds. |
| sMatrix.postTranslate(dst.left, dst.top); |
| shader.setLocalMatrix(sMatrix); |
| mBitmapPaint.setShader(shader); |
| |
| int oldAlpha = mBitmapPaint.getAlpha(); |
| mBitmapPaint.setAlpha((int) (oldAlpha * alpha)); |
| canvas.drawCircle(dst.centerX(), dst.centerY(), dst.width() / 2, |
| mBitmapPaint); |
| mBitmapPaint.setAlpha(oldAlpha); |
| |
| // Then draw the border. |
| canvas.drawCircle(dst.centerX(), dst.centerY(), |
| dst.width() / 2f - mBorderWidth / 2, mBorderPaint); |
| } |
| |
| @Override |
| public void setAlpha(int alpha) { |
| super.setAlpha(alpha); |
| |
| final int old = mBitmapPaint.getAlpha(); |
| mBitmapPaint.setAlpha(alpha); |
| if (alpha != old) { |
| invalidateSelf(); |
| } |
| } |
| |
| @Override |
| public void setColorFilter(ColorFilter cf) { |
| super.setColorFilter(cf); |
| mPaint.setColorFilter(cf); |
| } |
| } |