1ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee/* 2ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Copyright (C) 2014 The Android Open Source Project 3ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 4ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Licensed under the Apache License, Version 2.0 (the "License"); 5ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * you may not use this file except in compliance with the License. 6ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * You may obtain a copy of the License at 7ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 8ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * http://www.apache.org/licenses/LICENSE-2.0 9ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 10ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Unless required by applicable law or agreed to in writing, software 11ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * distributed under the License is distributed on an "AS IS" BASIS, 12ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * See the License for the specific language governing permissions and 14ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * limitations under the License. 15ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 16ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Leepackage android.support.v4.graphics.drawable; 17ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 18ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Leeimport android.content.res.Resources; 19ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Leeimport android.graphics.Bitmap; 20ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Leeimport android.graphics.BitmapShader; 21ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Leeimport android.graphics.Canvas; 22ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Leeimport android.graphics.ColorFilter; 233a1a3b98f843ab5c72644da9addb9473d895a826Chris Craikimport android.graphics.Matrix; 24ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Leeimport android.graphics.Paint; 25ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Leeimport android.graphics.PixelFormat; 26ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Leeimport android.graphics.Rect; 27ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Leeimport android.graphics.RectF; 28ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Leeimport android.graphics.Shader; 29ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Leeimport android.graphics.drawable.Drawable; 30ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Leeimport android.util.DisplayMetrics; 31ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Leeimport android.view.Gravity; 32ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 33ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee/** 34ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * A Drawable that wraps a bitmap and can be drawn with rounded corners. You can create a 35ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * RoundedBitmapDrawable from a file path, an input stream, or from a 36ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * {@link android.graphics.Bitmap} object. 37ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * <p> 38ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Also see the {@link android.graphics.Bitmap} class, which handles the management and 39ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * transformation of raw bitmap graphics, and should be used when drawing to a 40ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * {@link android.graphics.Canvas}. 41ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * </p> 42ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 439038afb70d70650d87659bb252181ca8645670b8Chris Craikpublic abstract class RoundedBitmapDrawable extends Drawable { 44ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee private static final int DEFAULT_PAINT_FLAGS = 453a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG; 463a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik final Bitmap mBitmap; 47ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT; 48ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee private int mGravity = Gravity.FILL; 493a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik private final Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS); 503a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik private final BitmapShader mBitmapShader; 513a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik private final Matrix mShaderMatrix = new Matrix(); 52ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee private float mCornerRadius; 53ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 549038afb70d70650d87659bb252181ca8645670b8Chris Craik final Rect mDstRect = new Rect(); // Gravity.apply() sets this 553a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik private final RectF mDstRectF = new RectF(); 56ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 57ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee private boolean mApplyGravity = true; 589265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss private boolean mIsCircular; 59ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 609265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss // These are scaled to match the target density. 61ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee private int mBitmapWidth; 62ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee private int mBitmapHeight; 63ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 64ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 65ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Returns the paint used to render this drawable. 66ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 67ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public final Paint getPaint() { 68ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mPaint; 69ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 70ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 71ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 72ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Returns the bitmap used by this drawable to render. May be null. 73ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 74ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public final Bitmap getBitmap() { 75ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mBitmap; 76ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 77ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 78ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee private void computeBitmapSize() { 79ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mBitmapWidth = mBitmap.getScaledWidth(mTargetDensity); 80ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mBitmapHeight = mBitmap.getScaledHeight(mTargetDensity); 81ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 82ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 83ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 84ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Set the density scale at which this drawable will be rendered. This 85ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * method assumes the drawable will be rendered at the same density as the 86ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * specified canvas. 87ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 88ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @param canvas The Canvas from which the density scale must be obtained. 89ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 90ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see android.graphics.Bitmap#setDensity(int) 91ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see android.graphics.Bitmap#getDensity() 92ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 93ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setTargetDensity(Canvas canvas) { 94ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee setTargetDensity(canvas.getDensity()); 95ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 96ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 97ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 98ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Set the density scale at which this drawable will be rendered. 99ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 100ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @param metrics The DisplayMetrics indicating the density scale for this drawable. 101ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 102ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see android.graphics.Bitmap#setDensity(int) 103ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see android.graphics.Bitmap#getDensity() 104ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 105ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setTargetDensity(DisplayMetrics metrics) { 106ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee setTargetDensity(metrics.densityDpi); 107ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 108ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 109ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 110ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Set the density at which this drawable will be rendered. 111ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 112ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @param density The density scale for this drawable. 113ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 114ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see android.graphics.Bitmap#setDensity(int) 115ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see android.graphics.Bitmap#getDensity() 116ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 117ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setTargetDensity(int density) { 118ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee if (mTargetDensity != density) { 119ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density; 120ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee if (mBitmap != null) { 121ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee computeBitmapSize(); 122ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 123ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee invalidateSelf(); 124ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 125ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 126ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 127ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 128ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Get the gravity used to position/stretch the bitmap within its bounds. 129ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 130ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @return the gravity applied to the bitmap 131ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 132ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see android.view.Gravity 133ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 134ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public int getGravity() { 135ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mGravity; 136ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 137ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 138ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 139ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Set the gravity used to position/stretch the bitmap within its bounds. 140ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 141ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @param gravity the gravity 142ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 143ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see android.view.Gravity 144ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 145ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setGravity(int gravity) { 146ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee if (mGravity != gravity) { 147ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mGravity = gravity; 148ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mApplyGravity = true; 149ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee invalidateSelf(); 150ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 151ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 152ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 153ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 154ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Enables or disables the mipmap hint for this drawable's bitmap. 155ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * See {@link Bitmap#setHasMipMap(boolean)} for more information. 156ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 157ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * If the bitmap is null, or the current API version does not support setting a mipmap hint, 158ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * calling this method has no effect. 159ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 160ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @param mipMap True if the bitmap should use mipmaps, false otherwise. 161ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 162ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see #hasMipMap() 163ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 164ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setMipMap(boolean mipMap) { 1659038afb70d70650d87659bb252181ca8645670b8Chris Craik throw new UnsupportedOperationException(); // must be overridden in subclasses 166ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 167ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 168ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 169ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Indicates whether the mipmap hint is enabled on this drawable's bitmap. 170ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 171ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @return True if the mipmap hint is set, false otherwise. If the bitmap 172ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * is null, this method always returns false. 173ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 174ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see #setMipMap(boolean) 175ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 176ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public boolean hasMipMap() { 1779038afb70d70650d87659bb252181ca8645670b8Chris Craik throw new UnsupportedOperationException(); // must be overridden in subclasses 178ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 179ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 180ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 181ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Enables or disables anti-aliasing for this drawable. Anti-aliasing affects 182ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * the edges of the bitmap only so it applies only when the drawable is rotated. 183ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 184ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @param aa True if the bitmap should be anti-aliased, false otherwise. 185ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 186ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see #hasAntiAlias() 187ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 188ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setAntiAlias(boolean aa) { 189ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mPaint.setAntiAlias(aa); 190ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee invalidateSelf(); 191ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 192ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 193ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 194ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Indicates whether anti-aliasing is enabled for this drawable. 195ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 196ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @return True if anti-aliasing is enabled, false otherwise. 197ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 198ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see #setAntiAlias(boolean) 199ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 200ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public boolean hasAntiAlias() { 201ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mPaint.isAntiAlias(); 202ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 203ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 204ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee @Override 205ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setFilterBitmap(boolean filter) { 206ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mPaint.setFilterBitmap(filter); 207ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee invalidateSelf(); 208ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 209ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 210ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee @Override 211ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setDither(boolean dither) { 212ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mPaint.setDither(dither); 213ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee invalidateSelf(); 214ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 215ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 2169038afb70d70650d87659bb252181ca8645670b8Chris Craik void gravityCompatApply(int gravity, int bitmapWidth, int bitmapHeight, 2179038afb70d70650d87659bb252181ca8645670b8Chris Craik Rect bounds, Rect outRect) { 2189038afb70d70650d87659bb252181ca8645670b8Chris Craik throw new UnsupportedOperationException(); 2199038afb70d70650d87659bb252181ca8645670b8Chris Craik } 2209038afb70d70650d87659bb252181ca8645670b8Chris Craik 2219038afb70d70650d87659bb252181ca8645670b8Chris Craik void updateDstRect() { 2229038afb70d70650d87659bb252181ca8645670b8Chris Craik if (mApplyGravity) { 2239265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss if (mIsCircular) { 2249265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss final int minDimen = Math.min(mBitmapWidth, mBitmapHeight); 2253a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik gravityCompatApply(mGravity, minDimen, minDimen, getBounds(), mDstRect); 2263a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik 2273a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik // inset the drawing rectangle to the largest contained square, 2283a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik // so that a circle will be drawn 2293a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik final int minDrawDimen = Math.min(mDstRect.width(), mDstRect.height()); 2303a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik final int insetX = Math.max(0, (mDstRect.width() - minDrawDimen) / 2); 2313a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik final int insetY = Math.max(0, (mDstRect.height() - minDrawDimen) / 2); 2323a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mDstRect.inset(insetX, insetY); 2333a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mCornerRadius = 0.5f * minDrawDimen; 2349265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } else { 2359265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss gravityCompatApply(mGravity, mBitmapWidth, mBitmapHeight, getBounds(), mDstRect); 2369265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } 2379038afb70d70650d87659bb252181ca8645670b8Chris Craik mDstRectF.set(mDstRect); 2383a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik 2393a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik if (mBitmapShader != null) { 2403a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik // setup shader matrix 2413a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mShaderMatrix.setTranslate(mDstRectF.left,mDstRectF.top); 2423a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mShaderMatrix.preScale( 2433a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mDstRectF.width() / mBitmap.getWidth(), 2443a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mDstRectF.height() / mBitmap.getHeight()); 2453a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mBitmapShader.setLocalMatrix(mShaderMatrix); 2463a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mPaint.setShader(mBitmapShader); 2473a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik } 2483a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik 2499038afb70d70650d87659bb252181ca8645670b8Chris Craik mApplyGravity = false; 2509038afb70d70650d87659bb252181ca8645670b8Chris Craik } 2519038afb70d70650d87659bb252181ca8645670b8Chris Craik } 2529038afb70d70650d87659bb252181ca8645670b8Chris Craik 253ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee @Override 254ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void draw(Canvas canvas) { 255ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee final Bitmap bitmap = mBitmap; 256ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee if (bitmap == null) { 257ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return; 258ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 259ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 2609038afb70d70650d87659bb252181ca8645670b8Chris Craik updateDstRect(); 2613a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik if (mPaint.getShader() == null) { 2623a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik canvas.drawBitmap(bitmap, null, mDstRect, mPaint); 263ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } else { 2643a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik canvas.drawRoundRect(mDstRectF, mCornerRadius, mCornerRadius, mPaint); 265ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 266ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 267ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 268ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee @Override 269ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setAlpha(int alpha) { 270ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee final int oldAlpha = mPaint.getAlpha(); 271ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee if (alpha != oldAlpha) { 272ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mPaint.setAlpha(alpha); 273ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee invalidateSelf(); 274ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 275ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 276ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 277ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public int getAlpha() { 278ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mPaint.getAlpha(); 279ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 280ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 281ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee @Override 282ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setColorFilter(ColorFilter cf) { 283ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mPaint.setColorFilter(cf); 284ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee invalidateSelf(); 285ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 286ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 287ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public ColorFilter getColorFilter() { 288ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mPaint.getColorFilter(); 289ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 290ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 291ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 2929265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss * Sets the image shape to circular. 2939265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss * <p>This overwrites any calls made to {@link #setCornerRadius(float)} so far.</p> 2949265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss */ 2959265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss public void setCircular(boolean circular) { 2969265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss mIsCircular = circular; 2979265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss mApplyGravity = true; 2989265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss if (circular) { 2999265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss updateCircularCornerRadius(); 3003a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mPaint.setShader(mBitmapShader); 3019265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss invalidateSelf(); 3029265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } else { 3039265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss setCornerRadius(0); 3049265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } 3059265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } 3069265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss 3079265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss private void updateCircularCornerRadius() { 3089265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss final int minCircularSize = Math.min(mBitmapHeight, mBitmapWidth); 3099265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss mCornerRadius = minCircularSize / 2; 3109265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } 3119265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss 3129265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss /** 3139265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss * @return <code>true</code> if the image is circular, else <code>false</code>. 3149265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss */ 3159265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss public boolean isCircular() { 3169265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss return mIsCircular; 3179265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } 3189265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss 3199265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss /** 320ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Sets the corner radius to be applied when drawing the bitmap. 321ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 322ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setCornerRadius(float cornerRadius) { 3233a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik if (mCornerRadius == cornerRadius) return; 3243a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik 3253a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mIsCircular = false; 326ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee if (isGreaterThanZero(cornerRadius)) { 327ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mPaint.setShader(mBitmapShader); 328ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } else { 329ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mPaint.setShader(null); 330ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 3313a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik 3323a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mCornerRadius = cornerRadius; 3333a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik invalidateSelf(); 3349265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } 3359265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss 3369265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss @Override 3379265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss protected void onBoundsChange(Rect bounds) { 3389265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss super.onBoundsChange(bounds); 3399265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss if (mIsCircular) { 3409265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss updateCircularCornerRadius(); 3419265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } 3423a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mApplyGravity = true; 343ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 344ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 345ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 346ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @return The corner radius applied when drawing the bitmap. 347ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 348ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public float getCornerRadius() { 349ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mCornerRadius; 350ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 351ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 352ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee @Override 353ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public int getIntrinsicWidth() { 354ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mBitmapWidth; 355ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 356ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 357ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee @Override 358ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public int getIntrinsicHeight() { 359ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mBitmapHeight; 360ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 361ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 362ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee @Override 363ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public int getOpacity() { 3649265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss if (mGravity != Gravity.FILL || mIsCircular) { 365ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return PixelFormat.TRANSLUCENT; 366ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 367ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee Bitmap bm = mBitmap; 368ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return (bm == null 369ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee || bm.hasAlpha() 370ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee || mPaint.getAlpha() < 255 371ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee || isGreaterThanZero(mCornerRadius)) 372ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; 373ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 374ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 3759038afb70d70650d87659bb252181ca8645670b8Chris Craik RoundedBitmapDrawable(Resources res, Bitmap bitmap) { 376ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee if (res != null) { 377ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mTargetDensity = res.getDisplayMetrics().densityDpi; 378ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 379ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 380ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mBitmap = bitmap; 381ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee if (mBitmap != null) { 382ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee computeBitmapSize(); 3833a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); 384ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } else { 385ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mBitmapWidth = mBitmapHeight = -1; 3863a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mBitmapShader = null; 387ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 388ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 389ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 3909038afb70d70650d87659bb252181ca8645670b8Chris Craik private static boolean isGreaterThanZero(float toCompare) { 3913a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik return toCompare > 0.05f; 392ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 393ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee} 394