BitmapDrawable.java revision fe7a18eeada1bf2553ca00afb71b372bd79666dd
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
19e222e359a0aab985488a711f6edb76820fe8c6dfChris Craikimport android.annotation.NonNull;
2012b97f5d2b15194ed6673c9838b13c8312157709Alan Viveretteimport android.content.res.ColorStateList;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources;
2252b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viveretteimport android.content.res.Resources.Theme;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Bitmap;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.BitmapFactory;
26b1216dd916e0f5fdec29684120c5bcc904800916Romain Guyimport android.graphics.BitmapShader;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.ColorFilter;
292356c5e69b0911e6334ebf6374217898371be5acAlan Viveretteimport android.graphics.Insets;
303f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglioimport android.graphics.Matrix;
31e222e359a0aab985488a711f6edb76820fe8c6dfChris Craikimport android.graphics.Outline;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Paint;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.PixelFormat;
34e7772d313b88e9fd3366670a9c8d1b145edef344Alan Viveretteimport android.graphics.PorterDuff;
35d9e788c4f0528e46db4a035cfac043736becb0d1Alan Viveretteimport android.graphics.PorterDuff.Mode;
3612b97f5d2b15194ed6673c9838b13c8312157709Alan Viveretteimport android.graphics.PorterDuffColorFilter;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Rect;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Shader;
3931049d76c55b18a6d9993f0d9687598740b16014Adam Powellimport android.graphics.Xfermode;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.DisplayMetrics;
423f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglioimport android.util.LayoutDirection;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Gravity;
44d9e788c4f0528e46db4a035cfac043736becb0d1Alan Viverette
4552b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viveretteimport com.android.internal.R;
4652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParser;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParserException;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A Drawable that wraps a bitmap and can be tiled, stretched, or aligned. You can create a
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * BitmapDrawable from a file path, an input stream, through XML inflation, or from
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a {@link android.graphics.Bitmap} object.
56dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * <p>It can be defined in an XML file with the <code>&lt;bitmap></code> element.  For more
57dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * information, see the guide to <a
58dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>
6012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette * Also see the {@link android.graphics.Bitmap} class, which handles the management and
6112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette * transformation of raw bitmap graphics, and should be used when drawing to a
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link android.graphics.Canvas}.
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </p>
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_src
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_antialias
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_filter
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_dither
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_gravity
70b40c1fdaee6e6cabea8d1ed78f56d5b6bd133cfbScott Main * @attr ref android.R.styleable#BitmapDrawable_mipMap
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_tileMode
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class BitmapDrawable extends Drawable {
74211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed    private static final int DEFAULT_PAINT_FLAGS =
75211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed            Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG;
760cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette
770cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    // Constants for {@link android.R.styleable#BitmapDrawable_tileMode}.
780cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    private static final int TILE_MODE_UNDEFINED = -2;
790cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    private static final int TILE_MODE_DISABLED = -1;
800cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    private static final int TILE_MODE_CLAMP = 0;
810cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    private static final int TILE_MODE_REPEAT = 1;
820cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    private static final int TILE_MODE_MIRROR = 2;
830cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette
84fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik    private final Rect mDstRect = new Rect();   // #updateDstRectAndInsetsIfDirty() sets this
850cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private BitmapState mBitmapState;
8712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    private PorterDuffColorFilter mTintFilter;
88c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn
890cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
91fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik    private boolean mDstRectAndInsetsDirty = true;
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mMutated;
9312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
94c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     // These are scaled to match the target density.
9511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    private int mBitmapWidth;
9611ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    private int mBitmapHeight;
973f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio
982356c5e69b0911e6334ebf6374217898371be5acAlan Viverette    /** Optical insets due to gravity. */
99fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik    private Insets mOpticalInsets = Insets.NONE;
1002356c5e69b0911e6334ebf6374217898371be5acAlan Viverette
1013f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    // Mirroring matrix for using with Shaders
1023f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    private Matrix mMirrorMatrix;
1033f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio
10411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    /**
10511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Create an empty drawable, not dealing with density.
1067ac40e38696aa74d7b7938add8fdbc47180ae424Romain Guy     * @deprecated Use {@link #BitmapDrawable(android.content.res.Resources, android.graphics.Bitmap)}
1077ac40e38696aa74d7b7938add8fdbc47180ae424Romain Guy     * instead to specify a bitmap to draw with and ensure the correct density is set.
10811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     */
1094a51c20ce607c74914f90fd897f04080121ac13bDianne Hackborn    @Deprecated
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public BitmapDrawable() {
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState = new BitmapState((Bitmap) null);
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    /**
11511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Create an empty drawable, setting initial target density based on
11611ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * the display metrics of the resources.
1170cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     *
1187ac40e38696aa74d7b7938add8fdbc47180ae424Romain Guy     * @deprecated Use {@link #BitmapDrawable(android.content.res.Resources, android.graphics.Bitmap)}
1197ac40e38696aa74d7b7938add8fdbc47180ae424Romain Guy     * instead to specify a bitmap to draw with.
12011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     */
1210cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    @SuppressWarnings("unused")
1227ac40e38696aa74d7b7938add8fdbc47180ae424Romain Guy    @Deprecated
12311ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    public BitmapDrawable(Resources res) {
12411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        mBitmapState = new BitmapState((Bitmap) null);
125c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        mBitmapState.mTargetDensity = mTargetDensity;
12611ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    }
12711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn
12811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    /**
12911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Create drawable from a bitmap, not dealing with density.
13011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @deprecated Use {@link #BitmapDrawable(Resources, Bitmap)} to ensure
13111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * that the drawable has correctly set its target density.
13211ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     */
1334a51c20ce607c74914f90fd897f04080121ac13bDianne Hackborn    @Deprecated
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public BitmapDrawable(Bitmap bitmap) {
13552b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        this(new BitmapState(bitmap), null, null);
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    /**
13911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Create drawable from a bitmap, setting initial target density based on
14011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * the display metrics of the resources.
14111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     */
14211ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    public BitmapDrawable(Resources res, Bitmap bitmap) {
14352b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        this(new BitmapState(bitmap), res, null);
144c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        mBitmapState.mTargetDensity = mTargetDensity;
14511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    }
14611ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn
147c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    /**
148c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * Create a drawable by opening a given file path and decoding the bitmap.
149c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * @deprecated Use {@link #BitmapDrawable(Resources, String)} to ensure
150c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * that the drawable has correctly set its target density.
151c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     */
15229e4a3c566f435c32f0b95e4ac8e8b33cac6fabaDianne Hackborn    @Deprecated
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public BitmapDrawable(String filepath) {
15452b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null, null);
1550cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (mBitmapState.mBitmap == null) {
156c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
157c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        }
158c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    }
159c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn
160c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    /**
161c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * Create a drawable by opening a given file path and decoding the bitmap.
162c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     */
1630cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    @SuppressWarnings("unused")
164c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    public BitmapDrawable(Resources res, String filepath) {
16552b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null, null);
166c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        mBitmapState.mTargetDensity = mTargetDensity;
1670cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (mBitmapState.mBitmap == null) {
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
172c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    /**
173c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * Create a drawable by decoding a bitmap from the given input stream.
174c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * @deprecated Use {@link #BitmapDrawable(Resources, java.io.InputStream)} to ensure
175c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * that the drawable has correctly set its target density.
176c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     */
17729e4a3c566f435c32f0b95e4ac8e8b33cac6fabaDianne Hackborn    @Deprecated
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public BitmapDrawable(java.io.InputStream is) {
17952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        this(new BitmapState(BitmapFactory.decodeStream(is)), null, null);
1800cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (mBitmapState.mBitmap == null) {
181c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
182c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        }
183c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    }
184c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn
185c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    /**
186c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * Create a drawable by decoding a bitmap from the given input stream.
187c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     */
1880cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    @SuppressWarnings("unused")
189c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    public BitmapDrawable(Resources res, java.io.InputStream is) {
19052b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        this(new BitmapState(BitmapFactory.decodeStream(is)), null, null);
191c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        mBitmapState.mTargetDensity = mTargetDensity;
1920cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (mBitmapState.mBitmap == null) {
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
197ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
198ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Returns the paint used to render this drawable.
199ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final Paint getPaint() {
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmapState.mPaint;
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
203ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy
204ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
205ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Returns the bitmap used by this drawable to render. May be null.
206ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final Bitmap getBitmap() {
2080cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        return mBitmapState.mBitmap;
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    private void computeBitmapSize() {
2120cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final Bitmap bitmap = mBitmapState.mBitmap;
2130cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (bitmap != null) {
2140cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            mBitmapWidth = bitmap.getScaledWidth(mTargetDensity);
2150cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            mBitmapHeight = bitmap.getScaledHeight(mTargetDensity);
2160cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        } else {
2170cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            mBitmapWidth = mBitmapHeight = -1;
2180cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        }
21911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    }
22012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void setBitmap(Bitmap bitmap) {
2220cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (mBitmapState.mBitmap != bitmap) {
2230cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            mBitmapState.mBitmap = bitmap;
2240cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            computeBitmapSize();
2259891e1fce5f29d0421d34aa481037417bd70853dChet Haase            invalidateSelf();
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set the density scale at which this drawable will be rendered. This
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * method assumes the drawable will be rendered at the same density as the
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * specified canvas.
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param canvas The Canvas from which the density scale must be obtained.
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
23611ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#setDensity(int)
23711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#getDensity()
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
23911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    public void setTargetDensity(Canvas canvas) {
24011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        setTargetDensity(canvas.getDensity());
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set the density scale at which this drawable will be rendered.
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param metrics The DisplayMetrics indicating the density scale for this drawable.
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
24811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#setDensity(int)
24911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#getDensity()
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
25111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    public void setTargetDensity(DisplayMetrics metrics) {
2529891e1fce5f29d0421d34aa481037417bd70853dChet Haase        setTargetDensity(metrics.densityDpi);
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
25611ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Set the density at which this drawable will be rendered.
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param density The density scale for this drawable.
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
26011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#setDensity(int)
26111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#getDensity()
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
26311ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    public void setTargetDensity(int density) {
2649891e1fce5f29d0421d34aa481037417bd70853dChet Haase        if (mTargetDensity != density) {
2659891e1fce5f29d0421d34aa481037417bd70853dChet Haase            mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
2660cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            if (mBitmapState.mBitmap != null) {
2679891e1fce5f29d0421d34aa481037417bd70853dChet Haase                computeBitmapSize();
2689891e1fce5f29d0421d34aa481037417bd70853dChet Haase            }
2699891e1fce5f29d0421d34aa481037417bd70853dChet Haase            invalidateSelf();
27011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        }
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Get the gravity used to position/stretch the bitmap within its bounds.
27411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * See android.view.Gravity
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the gravity applied to the bitmap
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getGravity() {
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmapState.mGravity;
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2805769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Set the gravity used to position/stretch the bitmap within its bounds.
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        See android.view.Gravity
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param gravity the gravity
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setGravity(int gravity) {
2869891e1fce5f29d0421d34aa481037417bd70853dChet Haase        if (mBitmapState.mGravity != gravity) {
2879891e1fce5f29d0421d34aa481037417bd70853dChet Haase            mBitmapState.mGravity = gravity;
288fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik            mDstRectAndInsetsDirty = true;
2899891e1fce5f29d0421d34aa481037417bd70853dChet Haase            invalidateSelf();
2909891e1fce5f29d0421d34aa481037417bd70853dChet Haase        }
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
293ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
2945769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * Enables or disables the mipmap hint for this drawable's bitmap.
2955769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * See {@link Bitmap#setHasMipMap(boolean)} for more information.
2965769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *
2975769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * If the bitmap is null calling this method has no effect.
2985769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *
2995769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * @param mipMap True if the bitmap should use mipmaps, false otherwise.
3005769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *
30112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     * @see #hasMipMap()
3025769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     */
3035769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    public void setMipMap(boolean mipMap) {
3045769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy        if (mBitmapState.mBitmap != null) {
3055769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy            mBitmapState.mBitmap.setHasMipMap(mipMap);
3065769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy            invalidateSelf();
3075769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy        }
3085769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    }
3095769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy
3105769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    /**
3115769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * Indicates whether the mipmap hint is enabled on this drawable's bitmap.
3125769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *
3135769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * @return True if the mipmap hint is set, false otherwise. If the bitmap
3145769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *         is null, this method always returns false.
3155769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *
31612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     * @see #setMipMap(boolean)
317b40c1fdaee6e6cabea8d1ed78f56d5b6bd133cfbScott Main     * @attr ref android.R.styleable#BitmapDrawable_mipMap
3185769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     */
3195769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    public boolean hasMipMap() {
3205769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy        return mBitmapState.mBitmap != null && mBitmapState.mBitmap.hasMipMap();
3215769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    }
3225769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy
3235769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    /**
324ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Enables or disables anti-aliasing for this drawable. Anti-aliasing affects
325ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * the edges of the bitmap only so it applies only when the drawable is rotated.
32612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
327ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @param aa True if the bitmap should be anti-aliased, false otherwise.
3285769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *
32912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     * @see #hasAntiAlias()
330ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setAntiAlias(boolean aa) {
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState.mPaint.setAntiAlias(aa);
3339891e1fce5f29d0421d34aa481037417bd70853dChet Haase        invalidateSelf();
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3355769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy
3365769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    /**
3375769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * Indicates whether anti-aliasing is enabled for this drawable.
3385769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *
3395769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * @return True if anti-aliasing is enabled, false otherwise.
3405769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *
3415769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * @see #setAntiAlias(boolean)
3425769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     */
3435769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    public boolean hasAntiAlias() {
3445769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy        return mBitmapState.mPaint.isAntiAlias();
3455769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    }
3465769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setFilterBitmap(boolean filter) {
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState.mPaint.setFilterBitmap(filter);
3509891e1fce5f29d0421d34aa481037417bd70853dChet Haase        invalidateSelf();
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setDither(boolean dither) {
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState.mPaint.setDither(dither);
3569891e1fce5f29d0421d34aa481037417bd70853dChet Haase        invalidateSelf();
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
359ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
360ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Indicates the repeat behavior of this drawable on the X axis.
36112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
3620cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * @return {@link android.graphics.Shader.TileMode#CLAMP} if the bitmap does not repeat,
3630cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     *         {@link android.graphics.Shader.TileMode#REPEAT} or
3640cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     *         {@link android.graphics.Shader.TileMode#MIRROR} otherwise.
365ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Shader.TileMode getTileModeX() {
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmapState.mTileModeX;
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
370ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
371ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Indicates the repeat behavior of this drawable on the Y axis.
37212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
3730cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * @return {@link android.graphics.Shader.TileMode#CLAMP} if the bitmap does not repeat,
3740cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     *         {@link android.graphics.Shader.TileMode#REPEAT} or
3750cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     *         {@link android.graphics.Shader.TileMode#MIRROR} otherwise.
37612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     */
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Shader.TileMode getTileModeY() {
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmapState.mTileModeY;
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
381ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
382ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Sets the repeat behavior of this drawable on the X axis. By default, the drawable
3830cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * does not repeat its bitmap. Using {@link android.graphics.Shader.TileMode#REPEAT} or
3840cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * {@link android.graphics.Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled)
3850cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * if the bitmap is smaller than this drawable.
38612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
387ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @param mode The repeat mode for this drawable.
38812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
38912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     * @see #setTileModeY(android.graphics.Shader.TileMode)
39012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     * @see #setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode)
3914f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette     * @attr ref android.R.styleable#BitmapDrawable_tileModeX
392ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setTileModeX(Shader.TileMode mode) {
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setTileModeXY(mode, mBitmapState.mTileModeY);
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
397ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
398ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Sets the repeat behavior of this drawable on the Y axis. By default, the drawable
3990cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * does not repeat its bitmap. Using {@link android.graphics.Shader.TileMode#REPEAT} or
4000cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * {@link android.graphics.Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled)
4010cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * if the bitmap is smaller than this drawable.
40212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
403ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @param mode The repeat mode for this drawable.
40412b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
40512b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     * @see #setTileModeX(android.graphics.Shader.TileMode)
40612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     * @see #setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode)
4074f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette     * @attr ref android.R.styleable#BitmapDrawable_tileModeY
40812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     */
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final void setTileModeY(Shader.TileMode mode) {
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setTileModeXY(mBitmapState.mTileModeX, mode);
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
413ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
414ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Sets the repeat behavior of this drawable on both axis. By default, the drawable
4150cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * does not repeat its bitmap. Using {@link android.graphics.Shader.TileMode#REPEAT} or
4160cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * {@link android.graphics.Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled)
4170cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * if the bitmap is smaller than this drawable.
41812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
419ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @param xmode The X repeat mode for this drawable.
420ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @param ymode The Y repeat mode for this drawable.
42112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
422ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @see #setTileModeX(android.graphics.Shader.TileMode)
42312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     * @see #setTileModeY(android.graphics.Shader.TileMode)
424ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setTileModeXY(Shader.TileMode xmode, Shader.TileMode ymode) {
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final BitmapState state = mBitmapState;
427ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy        if (state.mTileModeX != xmode || state.mTileModeY != ymode) {
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            state.mTileModeX = xmode;
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            state.mTileModeY = ymode;
4302660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy            state.mRebuildShader = true;
431fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik            mDstRectAndInsetsDirty = true;
4329891e1fce5f29d0421d34aa481037417bd70853dChet Haase            invalidateSelf();
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4373f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    public void setAutoMirrored(boolean mirrored) {
4383f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        if (mBitmapState.mAutoMirrored != mirrored) {
4393f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio            mBitmapState.mAutoMirrored = mirrored;
4403f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio            invalidateSelf();
4413f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        }
4423f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    }
4433f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio
4443f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    @Override
4453f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    public final boolean isAutoMirrored() {
4463f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        return mBitmapState.mAutoMirrored;
4473f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    }
4483f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio
4493f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    @Override
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getChangingConfigurations() {
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.getChangingConfigurations() | mBitmapState.mChangingConfigurations;
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4533f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio
4543f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    private boolean needMirroring() {
4553f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL;
4563f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    }
4573f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio
4583f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    private void updateMirrorMatrix(float dx) {
4593f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        if (mMirrorMatrix == null) {
4603f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio            mMirrorMatrix = new Matrix();
4613f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        }
4623f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        mMirrorMatrix.setTranslate(dx, 0);
4633f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        mMirrorMatrix.preScale(-1.0f, 1.0f);
4643f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    }
4653f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onBoundsChange(Rect bounds) {
468fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        mDstRectAndInsetsDirty = true;
4692356c5e69b0911e6334ebf6374217898371be5acAlan Viverette
4702356c5e69b0911e6334ebf6374217898371be5acAlan Viverette        final Shader shader = mBitmapState.mPaint.getShader();
4713f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        if (shader != null) {
4723f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio            if (needMirroring()) {
4733f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio                updateMirrorMatrix(bounds.right - bounds.left);
4743f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio                shader.setLocalMatrix(mMirrorMatrix);
475ab87983a11e0bd2e08d752d86d5e945ea7d39a04Leon Scroggins III                mBitmapState.mPaint.setShader(shader);
4763f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio            } else {
4773f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio                if (mMirrorMatrix != null) {
4783f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio                    mMirrorMatrix = null;
4793f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio                    shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
480ab87983a11e0bd2e08d752d86d5e945ea7d39a04Leon Scroggins III                    mBitmapState.mPaint.setShader(shader);
4813f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio                }
4823f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio            }
4833f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        }
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
48716f1d81d47beb1e04504a76de66e2919dde08c33Alan Viverette    public void draw(Canvas canvas) {
4880cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final Bitmap bitmap = mBitmapState.mBitmap;
48912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        if (bitmap == null) {
49012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            return;
49112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        }
49212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
49312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        final BitmapState state = mBitmapState;
49412b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        final Paint paint = state.mPaint;
49512b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        if (state.mRebuildShader) {
49612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            final Shader.TileMode tmx = state.mTileModeX;
49712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            final Shader.TileMode tmy = state.mTileModeY;
49812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            if (tmx == null && tmy == null) {
49912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                paint.setShader(null);
50012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            } else {
50112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                paint.setShader(new BitmapShader(bitmap,
50212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                        tmx == null ? Shader.TileMode.CLAMP : tmx,
50312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                        tmy == null ? Shader.TileMode.CLAMP : tmy));
50412b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            }
50512b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
50612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            state.mRebuildShader = false;
50712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        }
50812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
509307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette        final int restoreAlpha;
510307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette        if (state.mBaseAlpha != 1.0f) {
511307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette            final Paint p = getPaint();
512307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette            restoreAlpha = p.getAlpha();
513307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette            p.setAlpha((int) (restoreAlpha * state.mBaseAlpha + 0.5f));
514307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette        } else {
515307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette            restoreAlpha = -1;
516307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette        }
517307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette
51812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        final boolean clearColorFilter;
51912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        if (mTintFilter != null && paint.getColorFilter() == null) {
52012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            paint.setColorFilter(mTintFilter);
52112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            clearColorFilter = true;
52212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        } else {
52312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            clearColorFilter = false;
52412b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        }
52512b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
526fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        updateDstRectAndInsetsIfDirty();
52712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        final Shader shader = paint.getShader();
52812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        final boolean needMirroring = needMirroring();
52912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        if (shader == null) {
53012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            if (needMirroring) {
53112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                canvas.save();
53212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                // Mirror the bitmap
53312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                canvas.translate(mDstRect.right - mDstRect.left, 0);
53412b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                canvas.scale(-1.0f, 1.0f);
53512b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            }
53612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
53712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            canvas.drawBitmap(bitmap, null, mDstRect, paint);
53812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
53912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            if (needMirroring) {
54012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                canvas.restore();
54112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            }
54212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        } else {
54312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            if (needMirroring) {
54412b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                // Mirror the bitmap
54512b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                updateMirrorMatrix(mDstRect.right - mDstRect.left);
54612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                shader.setLocalMatrix(mMirrorMatrix);
547ab87983a11e0bd2e08d752d86d5e945ea7d39a04Leon Scroggins III                paint.setShader(shader);
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
54912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                if (mMirrorMatrix != null) {
55012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                    mMirrorMatrix = null;
55112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                    shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
552ab87983a11e0bd2e08d752d86d5e945ea7d39a04Leon Scroggins III                    paint.setShader(shader);
5533f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio                }
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
55512b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
55612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            canvas.drawRect(mDstRect, paint);
55712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        }
55812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
55912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        if (clearColorFilter) {
56012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            paint.setColorFilter(null);
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
562307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette
563307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette        if (restoreAlpha >= 0) {
564307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette            paint.setAlpha(restoreAlpha);
565307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette        }
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
568fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik    private void updateDstRectAndInsetsIfDirty() {
569fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        if (mDstRectAndInsetsDirty) {
570fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik            if (mBitmapState.mTileModeX == null && mBitmapState.mTileModeY == null) {
571fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                final Rect bounds = getBounds();
572fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                final int layoutDirection = getLayoutDirection();
573fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                Gravity.apply(mBitmapState.mGravity, mBitmapWidth, mBitmapHeight,
574fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                        bounds, mDstRect, layoutDirection);
575fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik
576fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                final int left = mDstRect.left - bounds.left;
577fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                final int top = mDstRect.top - bounds.top;
578fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                final int right = bounds.right - mDstRect.right;
579fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                final int bottom = bounds.bottom - mDstRect.bottom;
580fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                mOpticalInsets = Insets.of(left, top, right, bottom);
581fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik            } else {
582fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                copyBounds(mDstRect);
583fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                mOpticalInsets = Insets.NONE;
584fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik            }
585fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        }
586fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        mDstRectAndInsetsDirty = false;
587fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik    }
588fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik
589d30241541c3adcb126bb263ad8596e7902a6b5aeAlan Viverette    /**
590d30241541c3adcb126bb263ad8596e7902a6b5aeAlan Viverette     * @hide
591d30241541c3adcb126bb263ad8596e7902a6b5aeAlan Viverette     */
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5932356c5e69b0911e6334ebf6374217898371be5acAlan Viverette    public Insets getOpticalInsets() {
594fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        updateDstRectAndInsetsIfDirty();
595fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        return mOpticalInsets;
5962356c5e69b0911e6334ebf6374217898371be5acAlan Viverette    }
5972356c5e69b0911e6334ebf6374217898371be5acAlan Viverette
5982356c5e69b0911e6334ebf6374217898371be5acAlan Viverette    @Override
599e222e359a0aab985488a711f6edb76820fe8c6dfChris Craik    public void getOutline(@NonNull Outline outline) {
600fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        updateDstRectAndInsetsIfDirty();
601fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        outline.setRect(mDstRect);
602fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik
603fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        // Only opaque Bitmaps can report a non-0 alpha,
604fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        // since only they are guaranteed to fill their bounds
605fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        boolean opaqueOverShape = mBitmapState.mBitmap != null
606fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                && !mBitmapState.mBitmap.hasAlpha();
607fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        outline.setAlpha(opaqueOverShape ? getAlpha() / 255.0f : 0.0f);
608e222e359a0aab985488a711f6edb76820fe8c6dfChris Craik    }
609e222e359a0aab985488a711f6edb76820fe8c6dfChris Craik
610e222e359a0aab985488a711f6edb76820fe8c6dfChris Craik    @Override
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setAlpha(int alpha) {
61212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        final int oldAlpha = mBitmapState.mPaint.getAlpha();
613ad4f70306b2089a273635b73a101fe48aa36cbe2Chet Haase        if (alpha != oldAlpha) {
614ad4f70306b2089a273635b73a101fe48aa36cbe2Chet Haase            mBitmapState.mPaint.setAlpha(alpha);
615ad4f70306b2089a273635b73a101fe48aa36cbe2Chet Haase            invalidateSelf();
616ad4f70306b2089a273635b73a101fe48aa36cbe2Chet Haase        }
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
618b1af7f3d4be6cd6bc6e1e805f22c209e19bf928fChet Haase
619b1af7f3d4be6cd6bc6e1e805f22c209e19bf928fChet Haase    @Override
620b1af7f3d4be6cd6bc6e1e805f22c209e19bf928fChet Haase    public int getAlpha() {
621b1af7f3d4be6cd6bc6e1e805f22c209e19bf928fChet Haase        return mBitmapState.mPaint.getAlpha();
622b1af7f3d4be6cd6bc6e1e805f22c209e19bf928fChet Haase    }
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setColorFilter(ColorFilter cf) {
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState.mPaint.setColorFilter(cf);
6279891e1fce5f29d0421d34aa481037417bd70853dChet Haase        invalidateSelf();
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
630813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette    @Override
631813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette    public ColorFilter getColorFilter() {
632813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette        return mBitmapState.mPaint.getColorFilter();
633813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette    }
634813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette
635e7772d313b88e9fd3366670a9c8d1b145edef344Alan Viverette    @Override
636a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette    public void setTintList(ColorStateList tint) {
637a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        mBitmapState.mTint = tint;
638a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        mTintFilter = updateTintFilter(mTintFilter, tint, mBitmapState.mTintMode);
639a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        invalidateSelf();
640a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette    }
641b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
642a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette    @Override
643a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette    public void setTintMode(PorterDuff.Mode tintMode) {
644a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        mBitmapState.mTintMode = tintMode;
645a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        mTintFilter = updateTintFilter(mTintFilter, mBitmapState.mTint, tintMode);
646e7772d313b88e9fd3366670a9c8d1b145edef344Alan Viverette        invalidateSelf();
64712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    }
64812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
64912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    /**
650e7772d313b88e9fd3366670a9c8d1b145edef344Alan Viverette     * @hide only needed by a hack within ProgressBar
651813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette     */
652813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette    public ColorStateList getTint() {
653813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette        return mBitmapState.mTint;
654813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette    }
655813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette
656813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette    /**
6572f8ba8f7fad2b608102a9282219aaea2223e94f5Alan Viverette     * @hide only needed by a hack within ProgressBar
658af7c240b99506d2c81a72be738eb270ecaa39699Alan Viverette     */
659af7c240b99506d2c81a72be738eb270ecaa39699Alan Viverette    public Mode getTintMode() {
660af7c240b99506d2c81a72be738eb270ecaa39699Alan Viverette        return mBitmapState.mTintMode;
661af7c240b99506d2c81a72be738eb270ecaa39699Alan Viverette    }
662af7c240b99506d2c81a72be738eb270ecaa39699Alan Viverette
663813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette    /**
66431049d76c55b18a6d9993f0d9687598740b16014Adam Powell     * @hide Candidate for future API inclusion
66531049d76c55b18a6d9993f0d9687598740b16014Adam Powell     */
66652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    @Override
66731049d76c55b18a6d9993f0d9687598740b16014Adam Powell    public void setXfermode(Xfermode xfermode) {
66831049d76c55b18a6d9993f0d9687598740b16014Adam Powell        mBitmapState.mPaint.setXfermode(xfermode);
66931049d76c55b18a6d9993f0d9687598740b16014Adam Powell        invalidateSelf();
67031049d76c55b18a6d9993f0d9687598740b16014Adam Powell    }
67131049d76c55b18a6d9993f0d9687598740b16014Adam Powell
67231049d76c55b18a6d9993f0d9687598740b16014Adam Powell    /**
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * A mutable BitmapDrawable still shares its Bitmap with any other Drawable
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * that comes from the same resource.
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return This drawable.
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable mutate() {
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mMutated && super.mutate() == this) {
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mBitmapState = new BitmapState(mBitmapState);
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMutated = true;
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
68812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    protected boolean onStateChange(int[] stateSet) {
689b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        final BitmapState state = mBitmapState;
690b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        if (state.mTint != null && state.mTintMode != null) {
691b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
692b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            return true;
69312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        }
69412b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        return false;
69512b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    }
69612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
69712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    @Override
69812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    public boolean isStateful() {
69912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        final BitmapState s = mBitmapState;
70012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        return super.isStateful() || (s.mTint != null && s.mTint.isStateful());
70112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    }
70212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
70312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    @Override
70452b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws XmlPullParserException, IOException {
70652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        super.inflate(r, parser, attrs, theme);
70752b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7080cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.BitmapDrawable);
7090cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        updateStateFromTypedArray(a);
71006318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette        verifyState(a);
71152b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        a.recycle();
71252b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    }
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
71452b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    /**
71506318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette     * Ensures all required attributes are set.
71606318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette     *
71706318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette     * @throws XmlPullParserException if any required attributes are missing
71806318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette     */
71906318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette    private void verifyState(TypedArray a) throws XmlPullParserException {
72006318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette        final BitmapState state = mBitmapState;
72106318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette        if (state.mBitmap == null) {
72206318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette            throw new XmlPullParserException(a.getPositionDescription() +
72306318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette                    ": <bitmap> requires a valid src attribute");
72406318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette        }
72506318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette    }
72606318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette
72706318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette    /**
7280cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * Updates the constant state from the values in the typed array.
72952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette     */
7300cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
73152b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        final Resources r = a.getResources();
73212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        final BitmapState state = mBitmapState;
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7348e5e11b99fac942122ee2d6cdd30af51564861aeAlan Viverette        // Account for any configuration changes.
7358e5e11b99fac942122ee2d6cdd30af51564861aeAlan Viverette        state.mChangingConfigurations |= a.getChangingConfigurations();
7368e5e11b99fac942122ee2d6cdd30af51564861aeAlan Viverette
73752b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        // Extract the theme attributes, if any.
7388e5e11b99fac942122ee2d6cdd30af51564861aeAlan Viverette        state.mThemeAttrs = a.extractThemeAttrs();
73952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7400cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final int srcResId = a.getResourceId(R.styleable.BitmapDrawable_src, 0);
7410cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (srcResId != 0) {
7420cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            final Bitmap bitmap = BitmapFactory.decodeResource(r, srcResId);
74352b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            if (bitmap == null) {
74452b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette                throw new XmlPullParserException(a.getPositionDescription() +
74552b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette                        ": <bitmap> requires a valid src attribute");
74652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            }
7470cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette
74852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            state.mBitmap = bitmap;
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
75052b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7510cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        state.mTargetDensity = r.getDisplayMetrics().densityDpi;
75252b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7530cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final boolean defMipMap = state.mBitmap != null ? state.mBitmap.hasMipMap() : false;
7540cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        setMipMap(a.getBoolean(R.styleable.BitmapDrawable_mipMap, defMipMap));
75552b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7560cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        state.mAutoMirrored = a.getBoolean(
7570cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette                R.styleable.BitmapDrawable_autoMirrored, state.mAutoMirrored);
7580cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        state.mBaseAlpha = a.getFloat(R.styleable.BitmapDrawable_alpha, state.mBaseAlpha);
75952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7600cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final int tintMode = a.getInt(R.styleable.BitmapDrawable_tintMode, -1);
7610cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (tintMode != -1) {
7620cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
76352b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        }
76452b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7650cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final ColorStateList tint = a.getColorStateList(R.styleable.BitmapDrawable_tint);
7660cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (tint != null) {
7670cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            state.mTint = tint;
76852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        }
76952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
77052b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        final Paint paint = mBitmapState.mPaint;
7710cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        paint.setAntiAlias(a.getBoolean(
7720cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette                R.styleable.BitmapDrawable_antialias, paint.isAntiAlias()));
7730cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        paint.setFilterBitmap(a.getBoolean(
7740cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette                R.styleable.BitmapDrawable_filter, paint.isFilterBitmap()));
7750cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        paint.setDither(a.getBoolean(R.styleable.BitmapDrawable_dither, paint.isDither()));
77652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7770cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        setGravity(a.getInt(R.styleable.BitmapDrawable_gravity, state.mGravity));
77852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7790cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final int tileMode = a.getInt(R.styleable.BitmapDrawable_tileMode, TILE_MODE_UNDEFINED);
7800cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (tileMode != TILE_MODE_UNDEFINED) {
78122594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette            final Shader.TileMode mode = parseTileMode(tileMode);
78222594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette            setTileModeXY(mode, mode);
78322594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette        }
78422594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette
78522594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette        final int tileModeX = a.getInt(R.styleable.BitmapDrawable_tileModeX, TILE_MODE_UNDEFINED);
78622594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette        if (tileModeX != TILE_MODE_UNDEFINED) {
78722594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette            setTileModeX(parseTileMode(tileModeX));
78822594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette        }
78922594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette
79022594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette        final int tileModeY = a.getInt(R.styleable.BitmapDrawable_tileModeY, TILE_MODE_UNDEFINED);
79122594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette        if (tileModeY != TILE_MODE_UNDEFINED) {
79222594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette            setTileModeY(parseTileMode(tileModeY));
79352b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        }
7940cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette
7950cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        // Update local properties.
7960cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        initializeWithState(state, r);
79752b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    }
79852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
79952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    @Override
80052b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    public void applyTheme(Theme t) {
80152b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        super.applyTheme(t);
80252b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
80352b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        final BitmapState state = mBitmapState;
8040cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (state == null || state.mThemeAttrs == null) {
8050cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            return;
80652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        }
80752b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
8080cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.BitmapDrawable);
8090cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        try {
81052b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            updateStateFromTypedArray(a);
8110cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        } catch (XmlPullParserException e) {
8120cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            throw new RuntimeException(e);
8130cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        } finally {
81452b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            a.recycle();
81552b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        }
81652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    }
81752b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
81822594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette    private static Shader.TileMode parseTileMode(int tileMode) {
81952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        switch (tileMode) {
8200cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            case TILE_MODE_CLAMP:
82122594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette                return Shader.TileMode.CLAMP;
8220cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            case TILE_MODE_REPEAT:
82322594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette                return Shader.TileMode.REPEAT;
8240cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            case TILE_MODE_MIRROR:
82522594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette                return Shader.TileMode.MIRROR;
82622594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette            default:
82722594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette                return null;
82852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        }
82952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    }
83052b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
83152b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    @Override
83252b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    public boolean canApplyTheme() {
83352b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        return mBitmapState != null && mBitmapState.mThemeAttrs != null;
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getIntrinsicWidth() {
83811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        return mBitmapWidth;
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getIntrinsicHeight() {
84311ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        return mBitmapHeight;
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getOpacity() {
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mBitmapState.mGravity != Gravity.FILL) {
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return PixelFormat.TRANSLUCENT;
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8510cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette
8520cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final Bitmap bitmap = mBitmapState.mBitmap;
8530cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        return (bitmap == null || bitmap.hasAlpha() || mBitmapState.mPaint.getAlpha() < 255) ?
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final ConstantState getConstantState() {
8596efd2bad954e0e5bd74916a32f036a0f149dcd4dChristopher Lais        mBitmapState.mChangingConfigurations = getChangingConfigurations();
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmapState;
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final static class BitmapState extends ConstantState {
8640cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final Paint mPaint;
8650cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette
8660cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        // Values loaded during inflation.
8670cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        int[] mThemeAttrs = null;
8680cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        Bitmap mBitmap = null;
8690cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        ColorStateList mTint = null;
87009ceac298cc12471e4575fe49f97766c1ed7b2a1Alan Viverette        Mode mTintMode = Mode.SRC_IN;
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int mGravity = Gravity.FILL;
872307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette        float mBaseAlpha = 1.0f;
873ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy        Shader.TileMode mTileModeX = null;
874ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy        Shader.TileMode mTileModeY = null;
87511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
8760cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        boolean mAutoMirrored = false;
8770cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette
8780cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        int mChangingConfigurations;
8792660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy        boolean mRebuildShader;
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BitmapState(Bitmap bitmap) {
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mBitmap = bitmap;
8830cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            mPaint = new Paint(DEFAULT_PAINT_FLAGS);
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BitmapState(BitmapState bitmapState) {
887d9e788c4f0528e46db4a035cfac043736becb0d1Alan Viverette            mBitmap = bitmapState.mBitmap;
88812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            mTint = bitmapState.mTint;
88912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            mTintMode = bitmapState.mTintMode;
89052b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            mThemeAttrs = bitmapState.mThemeAttrs;
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mChangingConfigurations = bitmapState.mChangingConfigurations;
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mGravity = bitmapState.mGravity;
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTileModeX = bitmapState.mTileModeX;
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTileModeY = bitmapState.mTileModeY;
89511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn            mTargetDensity = bitmapState.mTargetDensity;
896307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette            mBaseAlpha = bitmapState.mBaseAlpha;
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPaint = new Paint(bitmapState.mPaint);
8982660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy            mRebuildShader = bitmapState.mRebuildShader;
8993f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio            mAutoMirrored = bitmapState.mAutoMirrored;
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
90352b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        public boolean canApplyTheme() {
90452b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            return mThemeAttrs != null;
90552b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        }
90652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
90752b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        @Override
9083b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        public Bitmap getBitmap() {
9093b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            return mBitmap;
9103b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        }
9113b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
9123b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        @Override
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Drawable newDrawable() {
91452b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            return new BitmapDrawable(this, null, null);
915c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        }
9162660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy
917c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        @Override
918c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        public Drawable newDrawable(Resources res) {
91952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            return new BitmapDrawable(this, res, null);
92052b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        }
92152b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
92252b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        @Override
92352b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        public Drawable newDrawable(Resources res, Theme theme) {
92452b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            return new BitmapDrawable(this, res, theme);
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9262660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getChangingConfigurations() {
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mChangingConfigurations;
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9330cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    /**
9340cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * The one constructor to rule them all. This is called by all public
9350cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * constructors to set the state and initialize local properties.
9360cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     */
93752b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    private BitmapDrawable(BitmapState state, Resources res, Theme theme) {
93852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        if (theme != null && state.canApplyTheme()) {
93906318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette            // If we need to apply a theme, implicitly mutate.
94052b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            mBitmapState = new BitmapState(state);
94152b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            applyTheme(theme);
94252b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        } else {
94352b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            mBitmapState = state;
94452b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        }
94552b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
94652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        initializeWithState(state, res);
94752b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    }
94812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
94952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    /**
95022594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette     * Initializes local dynamic properties from state. This should be called
95122594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette     * after significant state changes, e.g. from the One True Constructor and
95222594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette     * after inflating or applying a theme.
95352b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette     */
95452b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    private void initializeWithState(BitmapState state, Resources res) {
955c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        if (res != null) {
956c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            mTargetDensity = res.getDisplayMetrics().densityDpi;
957c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        } else {
958e42143aa575dcb8ab0616080b2e9b4614a1a4167Jozef BABJAK            mTargetDensity = state.mTargetDensity;
959c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        }
96012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
9615adf8ee451085ed6106b7dbadc6d8dcd9d90722bAlan Viverette        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
9620cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        computeBitmapSize();
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
965