BitmapDrawable.java revision ad4f70306b2089a273635b73a101fe48aa36cbe2
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.graphics.drawable;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Bitmap;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.BitmapFactory;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.ColorFilter;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Paint;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.PixelFormat;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Rect;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Shader;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.BitmapShader;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.DisplayMetrics;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Gravity;
33c0053223bedf33581b0830fb87be32c1f26e5372Fabrice Di Meglioimport android.view.View;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParser;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParserException;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A Drawable that wraps a bitmap and can be tiled, stretched, or aligned. You can create a
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * BitmapDrawable from a file path, an input stream, through XML inflation, or from
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a {@link android.graphics.Bitmap} object.
44dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * <p>It can be defined in an XML file with the <code>&lt;bitmap></code> element.  For more
45dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * information, see the guide to <a
46dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Also see the {@link android.graphics.Bitmap} class, which handles the management and
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * transformation of raw bitmap graphics, and should be used when drawing to a
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link android.graphics.Canvas}.
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </p>
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_src
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_antialias
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_filter
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_dither
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_gravity
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_tileMode
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class BitmapDrawable extends Drawable {
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
62211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed    private static final int DEFAULT_PAINT_FLAGS =
63211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed            Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private BitmapState mBitmapState;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Bitmap mBitmap;
66c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    private int mTargetDensity;
67c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Rect mDstRect = new Rect();   // Gravity.apply() sets this
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mApplyGravity;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mMutated;
7211ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn
73c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     // These are scaled to match the target density.
7411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    private int mBitmapWidth;
7511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    private int mBitmapHeight;
7611ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn
7711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    /**
7811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Create an empty drawable, not dealing with density.
7911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @deprecated Use {@link #BitmapDrawable(Resources)} to ensure
8011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * that the drawable has correctly set its target density.
8111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     */
824a51c20ce607c74914f90fd897f04080121ac13bDianne Hackborn    @Deprecated
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public BitmapDrawable() {
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState = new BitmapState((Bitmap) null);
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    /**
8811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Create an empty drawable, setting initial target density based on
8911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * the display metrics of the resources.
9011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     */
91ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    @SuppressWarnings({"UnusedParameters"})
9211ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    public BitmapDrawable(Resources res) {
9311ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        mBitmapState = new BitmapState((Bitmap) null);
94c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        mBitmapState.mTargetDensity = mTargetDensity;
9511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    }
9611ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn
9711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    /**
9811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Create drawable from a bitmap, not dealing with density.
9911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @deprecated Use {@link #BitmapDrawable(Resources, Bitmap)} to ensure
10011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * that the drawable has correctly set its target density.
10111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     */
1024a51c20ce607c74914f90fd897f04080121ac13bDianne Hackborn    @Deprecated
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public BitmapDrawable(Bitmap bitmap) {
104c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        this(new BitmapState(bitmap), null);
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    /**
10811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Create drawable from a bitmap, setting initial target density based on
10911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * the display metrics of the resources.
11011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     */
11111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    public BitmapDrawable(Resources res, Bitmap bitmap) {
112c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        this(new BitmapState(bitmap), res);
113c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        mBitmapState.mTargetDensity = mTargetDensity;
11411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    }
11511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn
116c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    /**
117c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * Create a drawable by opening a given file path and decoding the bitmap.
118c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * @deprecated Use {@link #BitmapDrawable(Resources, String)} to ensure
119c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * that the drawable has correctly set its target density.
120c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     */
12129e4a3c566f435c32f0b95e4ac8e8b33cac6fabaDianne Hackborn    @Deprecated
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public BitmapDrawable(String filepath) {
123c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
124c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        if (mBitmap == null) {
125c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
126c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        }
127c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    }
128c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn
129c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    /**
130c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * Create a drawable by opening a given file path and decoding the bitmap.
131c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     */
132ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    @SuppressWarnings({"UnusedParameters"})
133c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    public BitmapDrawable(Resources res, String filepath) {
134c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
135c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        mBitmapState.mTargetDensity = mTargetDensity;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mBitmap == null) {
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
141c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    /**
142c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * Create a drawable by decoding a bitmap from the given input stream.
143c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * @deprecated Use {@link #BitmapDrawable(Resources, java.io.InputStream)} to ensure
144c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * that the drawable has correctly set its target density.
145c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     */
14629e4a3c566f435c32f0b95e4ac8e8b33cac6fabaDianne Hackborn    @Deprecated
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public BitmapDrawable(java.io.InputStream is) {
148c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        this(new BitmapState(BitmapFactory.decodeStream(is)), null);
149c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        if (mBitmap == null) {
150c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
151c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        }
152c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    }
153c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn
154c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    /**
155c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * Create a drawable by decoding a bitmap from the given input stream.
156c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     */
157ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    @SuppressWarnings({"UnusedParameters"})
158c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    public BitmapDrawable(Resources res, java.io.InputStream is) {
159c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        this(new BitmapState(BitmapFactory.decodeStream(is)), null);
160c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        mBitmapState.mTargetDensity = mTargetDensity;
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mBitmap == null) {
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
166ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
167ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Returns the paint used to render this drawable.
168ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final Paint getPaint() {
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmapState.mPaint;
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
172ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy
173ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
174ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Returns the bitmap used by this drawable to render. May be null.
175ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final Bitmap getBitmap() {
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmap;
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    private void computeBitmapSize() {
18111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        mBitmapWidth = mBitmap.getScaledWidth(mTargetDensity);
18211ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        mBitmapHeight = mBitmap.getScaledHeight(mTargetDensity);
18311ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    }
18411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void setBitmap(Bitmap bitmap) {
1869891e1fce5f29d0421d34aa481037417bd70853dChet Haase        if (bitmap != mBitmap) {
1879891e1fce5f29d0421d34aa481037417bd70853dChet Haase            mBitmap = bitmap;
1889891e1fce5f29d0421d34aa481037417bd70853dChet Haase            if (bitmap != null) {
1899891e1fce5f29d0421d34aa481037417bd70853dChet Haase                computeBitmapSize();
1909891e1fce5f29d0421d34aa481037417bd70853dChet Haase            } else {
1919891e1fce5f29d0421d34aa481037417bd70853dChet Haase                mBitmapWidth = mBitmapHeight = -1;
1929891e1fce5f29d0421d34aa481037417bd70853dChet Haase            }
1939891e1fce5f29d0421d34aa481037417bd70853dChet Haase            invalidateSelf();
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set the density scale at which this drawable will be rendered. This
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * method assumes the drawable will be rendered at the same density as the
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * specified canvas.
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param canvas The Canvas from which the density scale must be obtained.
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
20411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#setDensity(int)
20511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#getDensity()
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
20711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    public void setTargetDensity(Canvas canvas) {
20811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        setTargetDensity(canvas.getDensity());
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set the density scale at which this drawable will be rendered.
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param metrics The DisplayMetrics indicating the density scale for this drawable.
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
21611ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#setDensity(int)
21711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#getDensity()
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
21911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    public void setTargetDensity(DisplayMetrics metrics) {
2209891e1fce5f29d0421d34aa481037417bd70853dChet Haase        setTargetDensity(metrics.densityDpi);
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
22411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Set the density at which this drawable will be rendered.
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param density The density scale for this drawable.
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
22811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#setDensity(int)
22911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#getDensity()
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
23111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    public void setTargetDensity(int density) {
2329891e1fce5f29d0421d34aa481037417bd70853dChet Haase        if (mTargetDensity != density) {
2339891e1fce5f29d0421d34aa481037417bd70853dChet Haase            mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
2349891e1fce5f29d0421d34aa481037417bd70853dChet Haase            if (mBitmap != null) {
2359891e1fce5f29d0421d34aa481037417bd70853dChet Haase                computeBitmapSize();
2369891e1fce5f29d0421d34aa481037417bd70853dChet Haase            }
2379891e1fce5f29d0421d34aa481037417bd70853dChet Haase            invalidateSelf();
23811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        }
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Get the gravity used to position/stretch the bitmap within its bounds.
24211ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * See android.view.Gravity
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the gravity applied to the bitmap
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getGravity() {
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmapState.mGravity;
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Set the gravity used to position/stretch the bitmap within its bounds.
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        See android.view.Gravity
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param gravity the gravity
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setGravity(int gravity) {
2549891e1fce5f29d0421d34aa481037417bd70853dChet Haase        if (mBitmapState.mGravity != gravity) {
2559891e1fce5f29d0421d34aa481037417bd70853dChet Haase            mBitmapState.mGravity = gravity;
2569891e1fce5f29d0421d34aa481037417bd70853dChet Haase            mApplyGravity = true;
2579891e1fce5f29d0421d34aa481037417bd70853dChet Haase            invalidateSelf();
2589891e1fce5f29d0421d34aa481037417bd70853dChet Haase        }
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
261ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
262ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Enables or disables anti-aliasing for this drawable. Anti-aliasing affects
263ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * the edges of the bitmap only so it applies only when the drawable is rotated.
264ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     *
265ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @param aa True if the bitmap should be anti-aliased, false otherwise.
266ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setAntiAlias(boolean aa) {
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState.mPaint.setAntiAlias(aa);
2699891e1fce5f29d0421d34aa481037417bd70853dChet Haase        invalidateSelf();
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setFilterBitmap(boolean filter) {
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState.mPaint.setFilterBitmap(filter);
2759891e1fce5f29d0421d34aa481037417bd70853dChet Haase        invalidateSelf();
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setDither(boolean dither) {
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState.mPaint.setDither(dither);
2819891e1fce5f29d0421d34aa481037417bd70853dChet Haase        invalidateSelf();
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
284ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
285ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Indicates the repeat behavior of this drawable on the X axis.
286ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     *
287ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @return {@link Shader.TileMode#CLAMP} if the bitmap does not repeat,
288ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     *         {@link Shader.TileMode#REPEAT} or {@link Shader.TileMode#MIRROR} otherwise.
289ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Shader.TileMode getTileModeX() {
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmapState.mTileModeX;
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
294ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
295ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Indicates the repeat behavior of this drawable on the Y axis.
296ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     *
297ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @return {@link Shader.TileMode#CLAMP} if the bitmap does not repeat,
298ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     *         {@link Shader.TileMode#REPEAT} or {@link Shader.TileMode#MIRROR} otherwise.
299ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Shader.TileMode getTileModeY() {
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmapState.mTileModeY;
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
304ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
305ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Sets the repeat behavior of this drawable on the X axis. By default, the drawable
306ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
307ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
308ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * is smaller than this drawable.
309ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     *
310ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @param mode The repeat mode for this drawable.
311ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     *
312ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @see #setTileModeY(android.graphics.Shader.TileMode)
313ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @see #setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode)
314ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setTileModeX(Shader.TileMode mode) {
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setTileModeXY(mode, mBitmapState.mTileModeY);
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
319ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
320ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Sets the repeat behavior of this drawable on the Y axis. By default, the drawable
321ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
322ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
323ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * is smaller than this drawable.
324ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     *
325ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @param mode The repeat mode for this drawable.
326ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     *
327ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @see #setTileModeX(android.graphics.Shader.TileMode)
328ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @see #setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode)
329ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final void setTileModeY(Shader.TileMode mode) {
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setTileModeXY(mBitmapState.mTileModeX, mode);
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
334ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
335ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Sets the repeat behavior of this drawable on both axis. By default, the drawable
336ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
337ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
338ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * is smaller than this drawable.
339ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     *
340ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @param xmode The X repeat mode for this drawable.
341ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @param ymode The Y repeat mode for this drawable.
342ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     *
343ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @see #setTileModeX(android.graphics.Shader.TileMode)
344ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @see #setTileModeY(android.graphics.Shader.TileMode)
345ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setTileModeXY(Shader.TileMode xmode, Shader.TileMode ymode) {
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final BitmapState state = mBitmapState;
348ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy        if (state.mTileModeX != xmode || state.mTileModeY != ymode) {
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            state.mTileModeX = xmode;
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            state.mTileModeY = ymode;
3512660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy            state.mRebuildShader = true;
3529891e1fce5f29d0421d34aa481037417bd70853dChet Haase            invalidateSelf();
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getChangingConfigurations() {
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.getChangingConfigurations() | mBitmapState.mChangingConfigurations;
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onBoundsChange(Rect bounds) {
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onBoundsChange(bounds);
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mApplyGravity = true;
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void draw(Canvas canvas) {
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Bitmap bitmap = mBitmap;
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (bitmap != null) {
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final BitmapState state = mBitmapState;
3722660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy            if (state.mRebuildShader) {
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Shader.TileMode tmx = state.mTileModeX;
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Shader.TileMode tmy = state.mTileModeY;
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (tmx == null && tmy == null) {
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    state.mPaint.setShader(null);
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
379ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy                    state.mPaint.setShader(new BitmapShader(bitmap,
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            tmx == null ? Shader.TileMode.CLAMP : tmx,
381ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy                            tmy == null ? Shader.TileMode.CLAMP : tmy));
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3832660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy                state.mRebuildShader = false;
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                copyBounds(mDstRect);
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Shader shader = state.mPaint.getShader();
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (shader == null) {
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mApplyGravity) {
390c0053223bedf33581b0830fb87be32c1f26e5372Fabrice Di Meglio                    final int layoutDirection = getResolvedLayoutDirectionSelf();
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Gravity.apply(state.mGravity, mBitmapWidth, mBitmapHeight,
392c0053223bedf33581b0830fb87be32c1f26e5372Fabrice Di Meglio                            getBounds(), mDstRect, layoutDirection);
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mApplyGravity = false;
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                canvas.drawBitmap(bitmap, null, mDstRect, state.mPaint);
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mApplyGravity) {
398ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy                    copyBounds(mDstRect);
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mApplyGravity = false;
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                canvas.drawRect(mDstRect, state.mPaint);
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setAlpha(int alpha) {
408ad4f70306b2089a273635b73a101fe48aa36cbe2Chet Haase        int oldAlpha = mBitmapState.mPaint.getAlpha();
409ad4f70306b2089a273635b73a101fe48aa36cbe2Chet Haase        if (alpha != oldAlpha) {
410ad4f70306b2089a273635b73a101fe48aa36cbe2Chet Haase            mBitmapState.mPaint.setAlpha(alpha);
411ad4f70306b2089a273635b73a101fe48aa36cbe2Chet Haase            invalidateSelf();
412ad4f70306b2089a273635b73a101fe48aa36cbe2Chet Haase        }
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setColorFilter(ColorFilter cf) {
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState.mPaint.setColorFilter(cf);
4189891e1fce5f29d0421d34aa481037417bd70853dChet Haase        invalidateSelf();
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * A mutable BitmapDrawable still shares its Bitmap with any other Drawable
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * that comes from the same resource.
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return This drawable.
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable mutate() {
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mMutated && super.mutate() == this) {
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mBitmapState = new BitmapState(mBitmapState);
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMutated = true;
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws XmlPullParserException, IOException {
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.inflate(r, parser, attrs);
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.BitmapDrawable);
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int id = a.getResourceId(com.android.internal.R.styleable.BitmapDrawable_src, 0);
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (id == 0) {
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new XmlPullParserException(parser.getPositionDescription() +
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ": <bitmap> requires a valid src attribute");
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Bitmap bitmap = BitmapFactory.decodeResource(r, id);
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (bitmap == null) {
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new XmlPullParserException(parser.getPositionDescription() +
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ": <bitmap> requires a valid src attribute");
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState.mBitmap = bitmap;
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setBitmap(bitmap);
45511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        setTargetDensity(r.getDisplayMetrics());
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Paint paint = mBitmapState.mPaint;
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        paint.setAntiAlias(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_antialias,
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                paint.isAntiAlias()));
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        paint.setFilterBitmap(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_filter,
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                paint.isFilterBitmap()));
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        paint.setDither(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_dither,
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                paint.isDither()));
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setGravity(a.getInt(com.android.internal.R.styleable.BitmapDrawable_gravity, Gravity.FILL));
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int tileMode = a.getInt(com.android.internal.R.styleable.BitmapDrawable_tileMode, -1);
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (tileMode != -1) {
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (tileMode) {
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case 0:
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    setTileModeXY(Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case 1:
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case 2:
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    setTileModeXY(Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        a.recycle();
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getIntrinsicWidth() {
48511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        return mBitmapWidth;
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getIntrinsicHeight() {
49011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        return mBitmapHeight;
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getOpacity() {
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mBitmapState.mGravity != Gravity.FILL) {
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return PixelFormat.TRANSLUCENT;
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Bitmap bm = mBitmap;
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (bm == null || bm.hasAlpha() || mBitmapState.mPaint.getAlpha() < 255) ?
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final ConstantState getConstantState() {
5056efd2bad954e0e5bd74916a32f036a0f149dcd4dChristopher Lais        mBitmapState.mChangingConfigurations = getChangingConfigurations();
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmapState;
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final static class BitmapState extends ConstantState {
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Bitmap mBitmap;
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int mChangingConfigurations;
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int mGravity = Gravity.FILL;
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS);
514ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy        Shader.TileMode mTileModeX = null;
515ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy        Shader.TileMode mTileModeY = null;
51611ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
5172660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy        boolean mRebuildShader;
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BitmapState(Bitmap bitmap) {
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mBitmap = bitmap;
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BitmapState(BitmapState bitmapState) {
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this(bitmapState.mBitmap);
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mChangingConfigurations = bitmapState.mChangingConfigurations;
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mGravity = bitmapState.mGravity;
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTileModeX = bitmapState.mTileModeX;
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTileModeY = bitmapState.mTileModeY;
52911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn            mTargetDensity = bitmapState.mTargetDensity;
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPaint = new Paint(bitmapState.mPaint);
5312660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy            mRebuildShader = bitmapState.mRebuildShader;
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Drawable newDrawable() {
536c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            return new BitmapDrawable(this, null);
537c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        }
5382660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy
539c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        @Override
540c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        public Drawable newDrawable(Resources res) {
541c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            return new BitmapDrawable(this, res);
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5432660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getChangingConfigurations() {
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mChangingConfigurations;
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
550c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    private BitmapDrawable(BitmapState state, Resources res) {
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState = state;
552c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        if (res != null) {
553c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            mTargetDensity = res.getDisplayMetrics().densityDpi;
554c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        } else {
555e42143aa575dcb8ab0616080b2e9b4614a1a4167Jozef BABJAK            mTargetDensity = state.mTargetDensity;
556c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        }
557ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy        setBitmap(state != null ? state.mBitmap : null);
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
560