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; 308f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viveretteimport android.support.annotation.RequiresApi; 31ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Leeimport android.util.DisplayMetrics; 32ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Leeimport android.view.Gravity; 33ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 34ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee/** 35ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * A Drawable that wraps a bitmap and can be drawn with rounded corners. You can create a 36ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * RoundedBitmapDrawable from a file path, an input stream, or from a 37ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * {@link android.graphics.Bitmap} object. 38ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * <p> 39ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Also see the {@link android.graphics.Bitmap} class, which handles the management and 40ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * transformation of raw bitmap graphics, and should be used when drawing to a 41ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * {@link android.graphics.Canvas}. 42ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * </p> 43ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 448f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viverette@RequiresApi(9) 459038afb70d70650d87659bb252181ca8645670b8Chris Craikpublic abstract class RoundedBitmapDrawable extends Drawable { 46ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee private static final int DEFAULT_PAINT_FLAGS = 473a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG; 483a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik final Bitmap mBitmap; 49ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT; 50ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee private int mGravity = Gravity.FILL; 513a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik private final Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS); 523a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik private final BitmapShader mBitmapShader; 533a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik private final Matrix mShaderMatrix = new Matrix(); 54ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee private float mCornerRadius; 55ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 569038afb70d70650d87659bb252181ca8645670b8Chris Craik final Rect mDstRect = new Rect(); // Gravity.apply() sets this 573a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik private final RectF mDstRectF = new RectF(); 58ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 59ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee private boolean mApplyGravity = true; 609265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss private boolean mIsCircular; 61ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 629265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss // These are scaled to match the target density. 63ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee private int mBitmapWidth; 64ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee private int mBitmapHeight; 65ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 66ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 67ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Returns the paint used to render this drawable. 68ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 69ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public final Paint getPaint() { 70ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mPaint; 71ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 72ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 73ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 74ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Returns the bitmap used by this drawable to render. May be null. 75ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 76ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public final Bitmap getBitmap() { 77ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mBitmap; 78ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 79ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 80ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee private void computeBitmapSize() { 81ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mBitmapWidth = mBitmap.getScaledWidth(mTargetDensity); 82ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mBitmapHeight = mBitmap.getScaledHeight(mTargetDensity); 83ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 84ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 85ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 86ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Set the density scale at which this drawable will be rendered. This 87ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * method assumes the drawable will be rendered at the same density as the 88ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * specified canvas. 89ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 90ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @param canvas The Canvas from which the density scale must be obtained. 91ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 92ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see android.graphics.Bitmap#setDensity(int) 93ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see android.graphics.Bitmap#getDensity() 94ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 95ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setTargetDensity(Canvas canvas) { 96ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee setTargetDensity(canvas.getDensity()); 97ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 98ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 99ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 100ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Set the density scale at which this drawable will be rendered. 101ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 102ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @param metrics The DisplayMetrics indicating the density scale for this drawable. 103ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 104ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see android.graphics.Bitmap#setDensity(int) 105ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see android.graphics.Bitmap#getDensity() 106ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 107ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setTargetDensity(DisplayMetrics metrics) { 108ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee setTargetDensity(metrics.densityDpi); 109ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 110ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 111ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 112ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Set the density at which this drawable will be rendered. 113ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 114ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @param density The density scale for this drawable. 115ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 116ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see android.graphics.Bitmap#setDensity(int) 117ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see android.graphics.Bitmap#getDensity() 118ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 119ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setTargetDensity(int density) { 120ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee if (mTargetDensity != density) { 121ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density; 122ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee if (mBitmap != null) { 123ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee computeBitmapSize(); 124ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 125ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee invalidateSelf(); 126ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 127ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 128ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 129ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 130ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Get the gravity used to position/stretch the bitmap within its bounds. 131ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 132ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @return the gravity applied to the bitmap 133ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 134ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see android.view.Gravity 135ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 136ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public int getGravity() { 137ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mGravity; 138ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 139ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 140ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 141ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Set the gravity used to position/stretch the bitmap within its bounds. 142ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 143ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @param gravity the gravity 144ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 145ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see android.view.Gravity 146ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 147ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setGravity(int gravity) { 148ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee if (mGravity != gravity) { 149ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mGravity = gravity; 150ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mApplyGravity = true; 151ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee invalidateSelf(); 152ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 153ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 154ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 155ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 156ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Enables or disables the mipmap hint for this drawable's bitmap. 157ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * See {@link Bitmap#setHasMipMap(boolean)} for more information. 158ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 159ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * If the bitmap is null, or the current API version does not support setting a mipmap hint, 160ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * calling this method has no effect. 161ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 162ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @param mipMap True if the bitmap should use mipmaps, false otherwise. 163ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 164ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see #hasMipMap() 165ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 166ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setMipMap(boolean mipMap) { 1679038afb70d70650d87659bb252181ca8645670b8Chris Craik throw new UnsupportedOperationException(); // must be overridden in subclasses 168ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 169ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 170ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 171ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Indicates whether the mipmap hint is enabled on this drawable's bitmap. 172ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 173ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @return True if the mipmap hint is set, false otherwise. If the bitmap 174ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * is null, this method always returns false. 175ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 176ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see #setMipMap(boolean) 177ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 178ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public boolean hasMipMap() { 1799038afb70d70650d87659bb252181ca8645670b8Chris Craik throw new UnsupportedOperationException(); // must be overridden in subclasses 180ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 181ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 182ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 183ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Enables or disables anti-aliasing for this drawable. Anti-aliasing affects 184ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * the edges of the bitmap only so it applies only when the drawable is rotated. 185ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 186ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @param aa True if the bitmap should be anti-aliased, false otherwise. 187ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 188ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see #hasAntiAlias() 189ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 190ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setAntiAlias(boolean aa) { 191ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mPaint.setAntiAlias(aa); 192ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee invalidateSelf(); 193ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 194ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 195ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 196ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Indicates whether anti-aliasing is enabled for this drawable. 197ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 198ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @return True if anti-aliasing is enabled, false otherwise. 199ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * 200ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @see #setAntiAlias(boolean) 201ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 202ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public boolean hasAntiAlias() { 203ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mPaint.isAntiAlias(); 204ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 205ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 206ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee @Override 207ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setFilterBitmap(boolean filter) { 208ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mPaint.setFilterBitmap(filter); 209ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee invalidateSelf(); 210ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 211ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 212ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee @Override 213ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setDither(boolean dither) { 214ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mPaint.setDither(dither); 215ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee invalidateSelf(); 216ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 217ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 2189038afb70d70650d87659bb252181ca8645670b8Chris Craik void gravityCompatApply(int gravity, int bitmapWidth, int bitmapHeight, 2199038afb70d70650d87659bb252181ca8645670b8Chris Craik Rect bounds, Rect outRect) { 2209038afb70d70650d87659bb252181ca8645670b8Chris Craik throw new UnsupportedOperationException(); 2219038afb70d70650d87659bb252181ca8645670b8Chris Craik } 2229038afb70d70650d87659bb252181ca8645670b8Chris Craik 2239038afb70d70650d87659bb252181ca8645670b8Chris Craik void updateDstRect() { 2249038afb70d70650d87659bb252181ca8645670b8Chris Craik if (mApplyGravity) { 2259265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss if (mIsCircular) { 2269265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss final int minDimen = Math.min(mBitmapWidth, mBitmapHeight); 2273a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik gravityCompatApply(mGravity, minDimen, minDimen, getBounds(), mDstRect); 2283a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik 2293a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik // inset the drawing rectangle to the largest contained square, 2303a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik // so that a circle will be drawn 2313a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik final int minDrawDimen = Math.min(mDstRect.width(), mDstRect.height()); 2323a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik final int insetX = Math.max(0, (mDstRect.width() - minDrawDimen) / 2); 2333a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik final int insetY = Math.max(0, (mDstRect.height() - minDrawDimen) / 2); 2343a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mDstRect.inset(insetX, insetY); 2353a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mCornerRadius = 0.5f * minDrawDimen; 2369265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } else { 2379265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss gravityCompatApply(mGravity, mBitmapWidth, mBitmapHeight, getBounds(), mDstRect); 2389265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } 2399038afb70d70650d87659bb252181ca8645670b8Chris Craik mDstRectF.set(mDstRect); 2403a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik 2413a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik if (mBitmapShader != null) { 2423a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik // setup shader matrix 2433a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mShaderMatrix.setTranslate(mDstRectF.left,mDstRectF.top); 2443a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mShaderMatrix.preScale( 2453a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mDstRectF.width() / mBitmap.getWidth(), 2463a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mDstRectF.height() / mBitmap.getHeight()); 2473a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mBitmapShader.setLocalMatrix(mShaderMatrix); 2483a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mPaint.setShader(mBitmapShader); 2493a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik } 2503a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik 2519038afb70d70650d87659bb252181ca8645670b8Chris Craik mApplyGravity = false; 2529038afb70d70650d87659bb252181ca8645670b8Chris Craik } 2539038afb70d70650d87659bb252181ca8645670b8Chris Craik } 2549038afb70d70650d87659bb252181ca8645670b8Chris Craik 255ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee @Override 256ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void draw(Canvas canvas) { 257ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee final Bitmap bitmap = mBitmap; 258ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee if (bitmap == null) { 259ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return; 260ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 261ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 2629038afb70d70650d87659bb252181ca8645670b8Chris Craik updateDstRect(); 2633a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik if (mPaint.getShader() == null) { 2643a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik canvas.drawBitmap(bitmap, null, mDstRect, mPaint); 265ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } else { 2663a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik canvas.drawRoundRect(mDstRectF, mCornerRadius, mCornerRadius, mPaint); 267ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 268ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 269ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 270ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee @Override 271ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setAlpha(int alpha) { 272ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee final int oldAlpha = mPaint.getAlpha(); 273ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee if (alpha != oldAlpha) { 274ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mPaint.setAlpha(alpha); 275ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee invalidateSelf(); 276ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 277ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 278ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 279e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 280ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public int getAlpha() { 281ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mPaint.getAlpha(); 282ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 283ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 284ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee @Override 285ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setColorFilter(ColorFilter cf) { 286ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mPaint.setColorFilter(cf); 287ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee invalidateSelf(); 288ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 289ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 290e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 291ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public ColorFilter getColorFilter() { 292ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mPaint.getColorFilter(); 293ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 294ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 295ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 2969265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss * Sets the image shape to circular. 2979265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss * <p>This overwrites any calls made to {@link #setCornerRadius(float)} so far.</p> 2989265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss */ 2999265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss public void setCircular(boolean circular) { 3009265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss mIsCircular = circular; 3019265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss mApplyGravity = true; 3029265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss if (circular) { 3039265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss updateCircularCornerRadius(); 3043a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mPaint.setShader(mBitmapShader); 3059265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss invalidateSelf(); 3069265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } else { 3079265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss setCornerRadius(0); 3089265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } 3099265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } 3109265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss 3119265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss private void updateCircularCornerRadius() { 3129265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss final int minCircularSize = Math.min(mBitmapHeight, mBitmapWidth); 3139265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss mCornerRadius = minCircularSize / 2; 3149265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } 3159265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss 3169265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss /** 3179265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss * @return <code>true</code> if the image is circular, else <code>false</code>. 3189265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss */ 3199265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss public boolean isCircular() { 3209265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss return mIsCircular; 3219265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } 3229265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss 3239265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss /** 324ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * Sets the corner radius to be applied when drawing the bitmap. 325ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 326ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public void setCornerRadius(float cornerRadius) { 3273a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik if (mCornerRadius == cornerRadius) return; 3283a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik 3293a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mIsCircular = false; 330ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee if (isGreaterThanZero(cornerRadius)) { 331ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mPaint.setShader(mBitmapShader); 332ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } else { 333ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mPaint.setShader(null); 334ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 3353a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik 3363a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mCornerRadius = cornerRadius; 3373a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik invalidateSelf(); 3389265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } 3399265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss 3409265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss @Override 3419265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss protected void onBoundsChange(Rect bounds) { 3429265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss super.onBoundsChange(bounds); 3439265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss if (mIsCircular) { 3449265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss updateCircularCornerRadius(); 3459265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss } 3463a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mApplyGravity = true; 347ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 348ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 349ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee /** 350ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee * @return The corner radius applied when drawing the bitmap. 351ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee */ 352ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public float getCornerRadius() { 353ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mCornerRadius; 354ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 355ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 356ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee @Override 357ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public int getIntrinsicWidth() { 358ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mBitmapWidth; 359ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 360ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 361ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee @Override 362ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public int getIntrinsicHeight() { 363ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return mBitmapHeight; 364ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 365ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 366ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee @Override 367ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee public int getOpacity() { 3689265673544525c1668786032195d5e6a1f370eb1Benjamin Weiss if (mGravity != Gravity.FILL || mIsCircular) { 369ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return PixelFormat.TRANSLUCENT; 370ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 371ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee Bitmap bm = mBitmap; 372ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee return (bm == null 373ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee || bm.hasAlpha() 374ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee || mPaint.getAlpha() < 255 375ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee || isGreaterThanZero(mCornerRadius)) 376ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; 377ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 378ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 3799038afb70d70650d87659bb252181ca8645670b8Chris Craik RoundedBitmapDrawable(Resources res, Bitmap bitmap) { 380ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee if (res != null) { 381ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mTargetDensity = res.getDisplayMetrics().densityDpi; 382ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 383ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 384ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mBitmap = bitmap; 385ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee if (mBitmap != null) { 386ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee computeBitmapSize(); 3873a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); 388ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } else { 389ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee mBitmapWidth = mBitmapHeight = -1; 3903a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik mBitmapShader = null; 391ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 392ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 393ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee 3949038afb70d70650d87659bb252181ca8645670b8Chris Craik private static boolean isGreaterThanZero(float toCompare) { 3953a1a3b98f843ab5c72644da9addb9473d895a826Chris Craik return toCompare > 0.05f; 396ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee } 397ddb24f29a236175d3cda4c11bda98a6212ecf9e5Yorke Lee} 398