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;
51dad7d84c04c5954b63ea8bb58c52b2291f44b4dfJohn Reckimport java.util.Collection;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A Drawable that wraps a bitmap and can be tiled, stretched, or aligned. You can create a
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * BitmapDrawable from a file path, an input stream, through XML inflation, or from
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a {@link android.graphics.Bitmap} object.
57dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * <p>It can be defined in an XML file with the <code>&lt;bitmap></code> element.  For more
58dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * information, see the guide to <a
59dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>
6112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette * Also see the {@link android.graphics.Bitmap} class, which handles the management and
6212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette * transformation of raw bitmap graphics, and should be used when drawing to a
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link android.graphics.Canvas}.
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </p>
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_src
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_antialias
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_filter
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_dither
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_gravity
71b40c1fdaee6e6cabea8d1ed78f56d5b6bd133cfbScott Main * @attr ref android.R.styleable#BitmapDrawable_mipMap
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#BitmapDrawable_tileMode
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class BitmapDrawable extends Drawable {
75211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed    private static final int DEFAULT_PAINT_FLAGS =
76211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed            Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG;
770cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette
780cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    // Constants for {@link android.R.styleable#BitmapDrawable_tileMode}.
790cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    private static final int TILE_MODE_UNDEFINED = -2;
800cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    private static final int TILE_MODE_DISABLED = -1;
810cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    private static final int TILE_MODE_CLAMP = 0;
820cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    private static final int TILE_MODE_REPEAT = 1;
830cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    private static final int TILE_MODE_MIRROR = 2;
840cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette
85fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik    private final Rect mDstRect = new Rect();   // #updateDstRectAndInsetsIfDirty() sets this
860cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private BitmapState mBitmapState;
8812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    private PorterDuffColorFilter mTintFilter;
89c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn
900cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
92fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik    private boolean mDstRectAndInsetsDirty = true;
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mMutated;
9412b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
95c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     // These are scaled to match the target density.
9611ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    private int mBitmapWidth;
9711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    private int mBitmapHeight;
983f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio
992356c5e69b0911e6334ebf6374217898371be5acAlan Viverette    /** Optical insets due to gravity. */
100fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik    private Insets mOpticalInsets = Insets.NONE;
1012356c5e69b0911e6334ebf6374217898371be5acAlan Viverette
1023f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    // Mirroring matrix for using with Shaders
1033f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    private Matrix mMirrorMatrix;
1043f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio
10511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    /**
10611ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Create an empty drawable, not dealing with density.
1077ac40e38696aa74d7b7938add8fdbc47180ae424Romain Guy     * @deprecated Use {@link #BitmapDrawable(android.content.res.Resources, android.graphics.Bitmap)}
1087ac40e38696aa74d7b7938add8fdbc47180ae424Romain Guy     * instead to specify a bitmap to draw with and ensure the correct density is set.
10911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     */
1104a51c20ce607c74914f90fd897f04080121ac13bDianne Hackborn    @Deprecated
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public BitmapDrawable() {
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState = new BitmapState((Bitmap) null);
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    /**
11611ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Create an empty drawable, setting initial target density based on
11711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * the display metrics of the resources.
1180cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     *
1197ac40e38696aa74d7b7938add8fdbc47180ae424Romain Guy     * @deprecated Use {@link #BitmapDrawable(android.content.res.Resources, android.graphics.Bitmap)}
1207ac40e38696aa74d7b7938add8fdbc47180ae424Romain Guy     * instead to specify a bitmap to draw with.
12111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     */
1220cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    @SuppressWarnings("unused")
1237ac40e38696aa74d7b7938add8fdbc47180ae424Romain Guy    @Deprecated
12411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    public BitmapDrawable(Resources res) {
12511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        mBitmapState = new BitmapState((Bitmap) null);
126c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        mBitmapState.mTargetDensity = mTargetDensity;
12711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    }
12811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn
12911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    /**
13011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Create drawable from a bitmap, not dealing with density.
13111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @deprecated Use {@link #BitmapDrawable(Resources, Bitmap)} to ensure
13211ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * that the drawable has correctly set its target density.
13311ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     */
1344a51c20ce607c74914f90fd897f04080121ac13bDianne Hackborn    @Deprecated
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public BitmapDrawable(Bitmap bitmap) {
13617cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette        this(new BitmapState(bitmap), null);
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    /**
14011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Create drawable from a bitmap, setting initial target density based on
14111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * the display metrics of the resources.
14211ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     */
14311ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    public BitmapDrawable(Resources res, Bitmap bitmap) {
14417cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette        this(new BitmapState(bitmap), res);
145c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        mBitmapState.mTargetDensity = mTargetDensity;
14611ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    }
14711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn
148c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    /**
149c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * Create a drawable by opening a given file path and decoding the bitmap.
150c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * @deprecated Use {@link #BitmapDrawable(Resources, String)} to ensure
151c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * that the drawable has correctly set its target density.
152c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     */
15329e4a3c566f435c32f0b95e4ac8e8b33cac6fabaDianne Hackborn    @Deprecated
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public BitmapDrawable(String filepath) {
15517cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
1560cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (mBitmapState.mBitmap == null) {
157c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
158c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        }
159c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    }
160c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn
161c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    /**
162c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * Create a drawable by opening a given file path and decoding the bitmap.
163c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     */
1640cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    @SuppressWarnings("unused")
165c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    public BitmapDrawable(Resources res, String filepath) {
16617cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
167c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        mBitmapState.mTargetDensity = mTargetDensity;
1680cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (mBitmapState.mBitmap == null) {
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
173c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    /**
174c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * Create a drawable by decoding a bitmap from the given input stream.
175c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * @deprecated Use {@link #BitmapDrawable(Resources, java.io.InputStream)} to ensure
176c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * that the drawable has correctly set its target density.
177c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     */
17829e4a3c566f435c32f0b95e4ac8e8b33cac6fabaDianne Hackborn    @Deprecated
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public BitmapDrawable(java.io.InputStream is) {
18017cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette        this(new BitmapState(BitmapFactory.decodeStream(is)), null);
1810cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (mBitmapState.mBitmap == null) {
182c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
183c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        }
184c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    }
185c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn
186c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    /**
187c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     * Create a drawable by decoding a bitmap from the given input stream.
188c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn     */
1890cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    @SuppressWarnings("unused")
190c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    public BitmapDrawable(Resources res, java.io.InputStream is) {
19117cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette        this(new BitmapState(BitmapFactory.decodeStream(is)), null);
192c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        mBitmapState.mTargetDensity = mTargetDensity;
1930cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (mBitmapState.mBitmap == null) {
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
198ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
199ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Returns the paint used to render this drawable.
200ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final Paint getPaint() {
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmapState.mPaint;
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
204ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy
205ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
206ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Returns the bitmap used by this drawable to render. May be null.
207ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final Bitmap getBitmap() {
2090cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        return mBitmapState.mBitmap;
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21211ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    private void computeBitmapSize() {
2130cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final Bitmap bitmap = mBitmapState.mBitmap;
2140cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (bitmap != null) {
2150cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            mBitmapWidth = bitmap.getScaledWidth(mTargetDensity);
2160cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            mBitmapHeight = bitmap.getScaledHeight(mTargetDensity);
2170cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        } else {
2180cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            mBitmapWidth = mBitmapHeight = -1;
2190cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        }
22011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    }
22112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void setBitmap(Bitmap bitmap) {
2230cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (mBitmapState.mBitmap != bitmap) {
2240cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            mBitmapState.mBitmap = bitmap;
2250cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            computeBitmapSize();
2269891e1fce5f29d0421d34aa481037417bd70853dChet Haase            invalidateSelf();
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set the density scale at which this drawable will be rendered. This
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * method assumes the drawable will be rendered at the same density as the
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * specified canvas.
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param canvas The Canvas from which the density scale must be obtained.
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
23711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#setDensity(int)
23811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#getDensity()
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
24011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    public void setTargetDensity(Canvas canvas) {
24111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        setTargetDensity(canvas.getDensity());
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set the density scale at which this drawable will be rendered.
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param metrics The DisplayMetrics indicating the density scale for this drawable.
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
24911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#setDensity(int)
25011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#getDensity()
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
25211ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    public void setTargetDensity(DisplayMetrics metrics) {
2539891e1fce5f29d0421d34aa481037417bd70853dChet Haase        setTargetDensity(metrics.densityDpi);
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
25711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Set the density at which this drawable will be rendered.
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param density The density scale for this drawable.
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
26111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#setDensity(int)
26211ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * @see android.graphics.Bitmap#getDensity()
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
26411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    public void setTargetDensity(int density) {
2659891e1fce5f29d0421d34aa481037417bd70853dChet Haase        if (mTargetDensity != density) {
2669891e1fce5f29d0421d34aa481037417bd70853dChet Haase            mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
2670cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            if (mBitmapState.mBitmap != null) {
2689891e1fce5f29d0421d34aa481037417bd70853dChet Haase                computeBitmapSize();
2699891e1fce5f29d0421d34aa481037417bd70853dChet Haase            }
2709891e1fce5f29d0421d34aa481037417bd70853dChet Haase            invalidateSelf();
27111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        }
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Get the gravity used to position/stretch the bitmap within its bounds.
27511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * See android.view.Gravity
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the gravity applied to the bitmap
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getGravity() {
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmapState.mGravity;
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2815769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Set the gravity used to position/stretch the bitmap within its bounds.
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        See android.view.Gravity
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param gravity the gravity
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setGravity(int gravity) {
2879891e1fce5f29d0421d34aa481037417bd70853dChet Haase        if (mBitmapState.mGravity != gravity) {
2889891e1fce5f29d0421d34aa481037417bd70853dChet Haase            mBitmapState.mGravity = gravity;
289fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik            mDstRectAndInsetsDirty = true;
2909891e1fce5f29d0421d34aa481037417bd70853dChet Haase            invalidateSelf();
2919891e1fce5f29d0421d34aa481037417bd70853dChet Haase        }
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
294ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
2955769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * Enables or disables the mipmap hint for this drawable's bitmap.
2965769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * See {@link Bitmap#setHasMipMap(boolean)} for more information.
2975769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *
2985769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * If the bitmap is null calling this method has no effect.
2995769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *
3005769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * @param mipMap True if the bitmap should use mipmaps, false otherwise.
3015769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *
30212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     * @see #hasMipMap()
3035769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     */
3045769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    public void setMipMap(boolean mipMap) {
3055769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy        if (mBitmapState.mBitmap != null) {
3065769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy            mBitmapState.mBitmap.setHasMipMap(mipMap);
3075769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy            invalidateSelf();
3085769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy        }
3095769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    }
3105769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy
3115769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    /**
3125769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * Indicates whether the mipmap hint is enabled on this drawable's bitmap.
3135769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *
3145769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * @return True if the mipmap hint is set, false otherwise. If the bitmap
3155769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *         is null, this method always returns false.
3165769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *
31712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     * @see #setMipMap(boolean)
318b40c1fdaee6e6cabea8d1ed78f56d5b6bd133cfbScott Main     * @attr ref android.R.styleable#BitmapDrawable_mipMap
3195769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     */
3205769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    public boolean hasMipMap() {
3215769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy        return mBitmapState.mBitmap != null && mBitmapState.mBitmap.hasMipMap();
3225769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    }
3235769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy
3245769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    /**
325ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Enables or disables anti-aliasing for this drawable. Anti-aliasing affects
326ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * the edges of the bitmap only so it applies only when the drawable is rotated.
32712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
328ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @param aa True if the bitmap should be anti-aliased, false otherwise.
3295769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *
33012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     * @see #hasAntiAlias()
331ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setAntiAlias(boolean aa) {
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState.mPaint.setAntiAlias(aa);
3349891e1fce5f29d0421d34aa481037417bd70853dChet Haase        invalidateSelf();
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3365769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy
3375769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    /**
3385769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * Indicates whether anti-aliasing is enabled for this drawable.
3395769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *
3405769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * @return True if anti-aliasing is enabled, false otherwise.
3415769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     *
3425769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     * @see #setAntiAlias(boolean)
3435769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy     */
3445769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    public boolean hasAntiAlias() {
3455769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy        return mBitmapState.mPaint.isAntiAlias();
3465769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy    }
3475769fcd88a6b53aa9394d869a9428c80e61a1565Romain Guy
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setFilterBitmap(boolean filter) {
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState.mPaint.setFilterBitmap(filter);
3519891e1fce5f29d0421d34aa481037417bd70853dChet Haase        invalidateSelf();
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setDither(boolean dither) {
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState.mPaint.setDither(dither);
3579891e1fce5f29d0421d34aa481037417bd70853dChet Haase        invalidateSelf();
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
360ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
361ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Indicates the repeat behavior of this drawable on the X axis.
36212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
3630cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * @return {@link android.graphics.Shader.TileMode#CLAMP} if the bitmap does not repeat,
3640cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     *         {@link android.graphics.Shader.TileMode#REPEAT} or
3650cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     *         {@link android.graphics.Shader.TileMode#MIRROR} otherwise.
366ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Shader.TileMode getTileModeX() {
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmapState.mTileModeX;
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
371ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
372ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Indicates the repeat behavior of this drawable on the Y axis.
37312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
3740cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * @return {@link android.graphics.Shader.TileMode#CLAMP} if the bitmap does not repeat,
3750cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     *         {@link android.graphics.Shader.TileMode#REPEAT} or
3760cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     *         {@link android.graphics.Shader.TileMode#MIRROR} otherwise.
37712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     */
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Shader.TileMode getTileModeY() {
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmapState.mTileModeY;
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
382ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
383ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Sets the repeat behavior of this drawable on the X axis. By default, the drawable
3840cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * does not repeat its bitmap. Using {@link android.graphics.Shader.TileMode#REPEAT} or
3850cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * {@link android.graphics.Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled)
3860cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * if the bitmap is smaller than this drawable.
38712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
388ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @param mode The repeat mode for this drawable.
38912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
39012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     * @see #setTileModeY(android.graphics.Shader.TileMode)
39112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     * @see #setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode)
3924f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette     * @attr ref android.R.styleable#BitmapDrawable_tileModeX
393ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setTileModeX(Shader.TileMode mode) {
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setTileModeXY(mode, mBitmapState.mTileModeY);
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
398ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
399ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Sets the repeat behavior of this drawable on the Y axis. By default, the drawable
4000cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * does not repeat its bitmap. Using {@link android.graphics.Shader.TileMode#REPEAT} or
4010cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * {@link android.graphics.Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled)
4020cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * if the bitmap is smaller than this drawable.
40312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
404ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @param mode The repeat mode for this drawable.
40512b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
40612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     * @see #setTileModeX(android.graphics.Shader.TileMode)
40712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     * @see #setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode)
4084f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette     * @attr ref android.R.styleable#BitmapDrawable_tileModeY
40912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     */
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final void setTileModeY(Shader.TileMode mode) {
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setTileModeXY(mBitmapState.mTileModeX, mode);
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
414ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy    /**
415ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * Sets the repeat behavior of this drawable on both axis. By default, the drawable
4160cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * does not repeat its bitmap. Using {@link android.graphics.Shader.TileMode#REPEAT} or
4170cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * {@link android.graphics.Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled)
4180cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * if the bitmap is smaller than this drawable.
41912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
420ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @param xmode The X repeat mode for this drawable.
421ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @param ymode The Y repeat mode for this drawable.
42212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     *
423ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     * @see #setTileModeX(android.graphics.Shader.TileMode)
42412b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette     * @see #setTileModeY(android.graphics.Shader.TileMode)
425ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy     */
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setTileModeXY(Shader.TileMode xmode, Shader.TileMode ymode) {
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final BitmapState state = mBitmapState;
428ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy        if (state.mTileModeX != xmode || state.mTileModeY != ymode) {
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            state.mTileModeX = xmode;
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            state.mTileModeY = ymode;
4312660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy            state.mRebuildShader = true;
432fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik            mDstRectAndInsetsDirty = true;
4339891e1fce5f29d0421d34aa481037417bd70853dChet Haase            invalidateSelf();
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4383f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    public void setAutoMirrored(boolean mirrored) {
4393f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        if (mBitmapState.mAutoMirrored != mirrored) {
4403f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio            mBitmapState.mAutoMirrored = mirrored;
4413f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio            invalidateSelf();
4423f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        }
4433f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    }
4443f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio
4453f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    @Override
4463f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    public final boolean isAutoMirrored() {
4473f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        return mBitmapState.mAutoMirrored;
4483f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    }
4493f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio
4503f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    @Override
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getChangingConfigurations() {
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.getChangingConfigurations() | mBitmapState.mChangingConfigurations;
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4543f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio
4553f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    private boolean needMirroring() {
4563f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL;
4573f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    }
4583f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio
4593f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    private void updateMirrorMatrix(float dx) {
4603f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        if (mMirrorMatrix == null) {
4613f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio            mMirrorMatrix = new Matrix();
4623f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        }
4633f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        mMirrorMatrix.setTranslate(dx, 0);
4643f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        mMirrorMatrix.preScale(-1.0f, 1.0f);
4653f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio    }
4663f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onBoundsChange(Rect bounds) {
469fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        mDstRectAndInsetsDirty = true;
4702356c5e69b0911e6334ebf6374217898371be5acAlan Viverette
4712356c5e69b0911e6334ebf6374217898371be5acAlan Viverette        final Shader shader = mBitmapState.mPaint.getShader();
4723f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        if (shader != null) {
4733f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio            if (needMirroring()) {
4743f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio                updateMirrorMatrix(bounds.right - bounds.left);
4753f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio                shader.setLocalMatrix(mMirrorMatrix);
476ab87983a11e0bd2e08d752d86d5e945ea7d39a04Leon Scroggins III                mBitmapState.mPaint.setShader(shader);
4773f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio            } else {
4783f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio                if (mMirrorMatrix != null) {
4793f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio                    mMirrorMatrix = null;
4803f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio                    shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
481ab87983a11e0bd2e08d752d86d5e945ea7d39a04Leon Scroggins III                    mBitmapState.mPaint.setShader(shader);
4823f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio                }
4833f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio            }
4843f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        }
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
48816f1d81d47beb1e04504a76de66e2919dde08c33Alan Viverette    public void draw(Canvas canvas) {
4890cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final Bitmap bitmap = mBitmapState.mBitmap;
49012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        if (bitmap == null) {
49112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            return;
49212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        }
49312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
49412b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        final BitmapState state = mBitmapState;
49512b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        final Paint paint = state.mPaint;
49612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        if (state.mRebuildShader) {
49712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            final Shader.TileMode tmx = state.mTileModeX;
49812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            final Shader.TileMode tmy = state.mTileModeY;
49912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            if (tmx == null && tmy == null) {
50012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                paint.setShader(null);
50112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            } else {
50212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                paint.setShader(new BitmapShader(bitmap,
50312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                        tmx == null ? Shader.TileMode.CLAMP : tmx,
50412b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                        tmy == null ? Shader.TileMode.CLAMP : tmy));
50512b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            }
50612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
50712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            state.mRebuildShader = false;
50812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        }
50912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
510307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette        final int restoreAlpha;
511307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette        if (state.mBaseAlpha != 1.0f) {
512307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette            final Paint p = getPaint();
513307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette            restoreAlpha = p.getAlpha();
514307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette            p.setAlpha((int) (restoreAlpha * state.mBaseAlpha + 0.5f));
515307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette        } else {
516307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette            restoreAlpha = -1;
517307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette        }
518307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette
51912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        final boolean clearColorFilter;
52012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        if (mTintFilter != null && paint.getColorFilter() == null) {
52112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            paint.setColorFilter(mTintFilter);
52212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            clearColorFilter = true;
52312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        } else {
52412b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            clearColorFilter = false;
52512b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        }
52612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
527fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        updateDstRectAndInsetsIfDirty();
52812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        final Shader shader = paint.getShader();
52912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        final boolean needMirroring = needMirroring();
53012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        if (shader == null) {
53112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            if (needMirroring) {
53212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                canvas.save();
53312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                // Mirror the bitmap
53412b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                canvas.translate(mDstRect.right - mDstRect.left, 0);
53512b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                canvas.scale(-1.0f, 1.0f);
53612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            }
53712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
53812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            canvas.drawBitmap(bitmap, null, mDstRect, paint);
53912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
54012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            if (needMirroring) {
54112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                canvas.restore();
54212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            }
54312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        } else {
54412b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            if (needMirroring) {
54512b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                // Mirror the bitmap
54612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                updateMirrorMatrix(mDstRect.right - mDstRect.left);
54712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                shader.setLocalMatrix(mMirrorMatrix);
548ab87983a11e0bd2e08d752d86d5e945ea7d39a04Leon Scroggins III                paint.setShader(shader);
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
55012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                if (mMirrorMatrix != null) {
55112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                    mMirrorMatrix = null;
55212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette                    shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
553ab87983a11e0bd2e08d752d86d5e945ea7d39a04Leon Scroggins III                    paint.setShader(shader);
5543f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio                }
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
55612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
55712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            canvas.drawRect(mDstRect, paint);
55812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        }
55912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
56012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        if (clearColorFilter) {
56112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            paint.setColorFilter(null);
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
563307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette
564307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette        if (restoreAlpha >= 0) {
565307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette            paint.setAlpha(restoreAlpha);
566307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette        }
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik    private void updateDstRectAndInsetsIfDirty() {
570fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        if (mDstRectAndInsetsDirty) {
571fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik            if (mBitmapState.mTileModeX == null && mBitmapState.mTileModeY == null) {
572fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                final Rect bounds = getBounds();
573fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                final int layoutDirection = getLayoutDirection();
574fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                Gravity.apply(mBitmapState.mGravity, mBitmapWidth, mBitmapHeight,
575fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                        bounds, mDstRect, layoutDirection);
576fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik
577fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                final int left = mDstRect.left - bounds.left;
578fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                final int top = mDstRect.top - bounds.top;
579fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                final int right = bounds.right - mDstRect.right;
580fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                final int bottom = bounds.bottom - mDstRect.bottom;
581fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                mOpticalInsets = Insets.of(left, top, right, bottom);
582fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik            } else {
583fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                copyBounds(mDstRect);
584fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                mOpticalInsets = Insets.NONE;
585fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik            }
586fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        }
587fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        mDstRectAndInsetsDirty = false;
588fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik    }
589fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik
590d30241541c3adcb126bb263ad8596e7902a6b5aeAlan Viverette    /**
591d30241541c3adcb126bb263ad8596e7902a6b5aeAlan Viverette     * @hide
592d30241541c3adcb126bb263ad8596e7902a6b5aeAlan Viverette     */
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5942356c5e69b0911e6334ebf6374217898371be5acAlan Viverette    public Insets getOpticalInsets() {
595fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        updateDstRectAndInsetsIfDirty();
596fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        return mOpticalInsets;
5972356c5e69b0911e6334ebf6374217898371be5acAlan Viverette    }
5982356c5e69b0911e6334ebf6374217898371be5acAlan Viverette
5992356c5e69b0911e6334ebf6374217898371be5acAlan Viverette    @Override
600e222e359a0aab985488a711f6edb76820fe8c6dfChris Craik    public void getOutline(@NonNull Outline outline) {
601fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        updateDstRectAndInsetsIfDirty();
602fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        outline.setRect(mDstRect);
603fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik
604fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        // Only opaque Bitmaps can report a non-0 alpha,
605fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        // since only they are guaranteed to fill their bounds
606fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        boolean opaqueOverShape = mBitmapState.mBitmap != null
607fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik                && !mBitmapState.mBitmap.hasAlpha();
608fe7a18eeada1bf2553ca00afb71b372bd79666ddChris Craik        outline.setAlpha(opaqueOverShape ? getAlpha() / 255.0f : 0.0f);
609e222e359a0aab985488a711f6edb76820fe8c6dfChris Craik    }
610e222e359a0aab985488a711f6edb76820fe8c6dfChris Craik
611e222e359a0aab985488a711f6edb76820fe8c6dfChris Craik    @Override
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setAlpha(int alpha) {
61312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        final int oldAlpha = mBitmapState.mPaint.getAlpha();
614ad4f70306b2089a273635b73a101fe48aa36cbe2Chet Haase        if (alpha != oldAlpha) {
615ad4f70306b2089a273635b73a101fe48aa36cbe2Chet Haase            mBitmapState.mPaint.setAlpha(alpha);
616ad4f70306b2089a273635b73a101fe48aa36cbe2Chet Haase            invalidateSelf();
617ad4f70306b2089a273635b73a101fe48aa36cbe2Chet Haase        }
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
619b1af7f3d4be6cd6bc6e1e805f22c209e19bf928fChet Haase
620b1af7f3d4be6cd6bc6e1e805f22c209e19bf928fChet Haase    @Override
621b1af7f3d4be6cd6bc6e1e805f22c209e19bf928fChet Haase    public int getAlpha() {
622b1af7f3d4be6cd6bc6e1e805f22c209e19bf928fChet Haase        return mBitmapState.mPaint.getAlpha();
623b1af7f3d4be6cd6bc6e1e805f22c209e19bf928fChet Haase    }
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setColorFilter(ColorFilter cf) {
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapState.mPaint.setColorFilter(cf);
6289891e1fce5f29d0421d34aa481037417bd70853dChet Haase        invalidateSelf();
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
631813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette    @Override
632813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette    public ColorFilter getColorFilter() {
633813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette        return mBitmapState.mPaint.getColorFilter();
634813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette    }
635813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette
636e7772d313b88e9fd3366670a9c8d1b145edef344Alan Viverette    @Override
637a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette    public void setTintList(ColorStateList tint) {
638a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        mBitmapState.mTint = tint;
639a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        mTintFilter = updateTintFilter(mTintFilter, tint, mBitmapState.mTintMode);
640a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        invalidateSelf();
641a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette    }
642b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
643a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette    @Override
644a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette    public void setTintMode(PorterDuff.Mode tintMode) {
645a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        mBitmapState.mTintMode = tintMode;
646a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        mTintFilter = updateTintFilter(mTintFilter, mBitmapState.mTint, tintMode);
647e7772d313b88e9fd3366670a9c8d1b145edef344Alan Viverette        invalidateSelf();
64812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    }
64912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
65012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    /**
651e7772d313b88e9fd3366670a9c8d1b145edef344Alan Viverette     * @hide only needed by a hack within ProgressBar
652813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette     */
653813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette    public ColorStateList getTint() {
654813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette        return mBitmapState.mTint;
655813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette    }
656813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette
657813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette    /**
6582f8ba8f7fad2b608102a9282219aaea2223e94f5Alan Viverette     * @hide only needed by a hack within ProgressBar
659af7c240b99506d2c81a72be738eb270ecaa39699Alan Viverette     */
660af7c240b99506d2c81a72be738eb270ecaa39699Alan Viverette    public Mode getTintMode() {
661af7c240b99506d2c81a72be738eb270ecaa39699Alan Viverette        return mBitmapState.mTintMode;
662af7c240b99506d2c81a72be738eb270ecaa39699Alan Viverette    }
663af7c240b99506d2c81a72be738eb270ecaa39699Alan Viverette
664813d85b82cb7cbaa5dbe05496d1038caa17a1698Alan Viverette    /**
66531049d76c55b18a6d9993f0d9687598740b16014Adam Powell     * @hide Candidate for future API inclusion
66631049d76c55b18a6d9993f0d9687598740b16014Adam Powell     */
66752b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    @Override
66831049d76c55b18a6d9993f0d9687598740b16014Adam Powell    public void setXfermode(Xfermode xfermode) {
66931049d76c55b18a6d9993f0d9687598740b16014Adam Powell        mBitmapState.mPaint.setXfermode(xfermode);
67031049d76c55b18a6d9993f0d9687598740b16014Adam Powell        invalidateSelf();
67131049d76c55b18a6d9993f0d9687598740b16014Adam Powell    }
67231049d76c55b18a6d9993f0d9687598740b16014Adam Powell
67331049d76c55b18a6d9993f0d9687598740b16014Adam Powell    /**
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * A mutable BitmapDrawable still shares its Bitmap with any other Drawable
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * that comes from the same resource.
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return This drawable.
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable mutate() {
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mMutated && super.mutate() == this) {
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mBitmapState = new BitmapState(mBitmapState);
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMutated = true;
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
688727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette    /**
689727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette     * @hide
690727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette     */
691727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette    public void clearMutated() {
692727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette        super.clearMutated();
693727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette        mMutated = false;
694727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette    }
695727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
69712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    protected boolean onStateChange(int[] stateSet) {
698b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        final BitmapState state = mBitmapState;
699b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        if (state.mTint != null && state.mTintMode != null) {
700b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
701b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            return true;
70212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        }
70312b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        return false;
70412b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    }
70512b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
70612b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    @Override
70712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    public boolean isStateful() {
70812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        final BitmapState s = mBitmapState;
70912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        return super.isStateful() || (s.mTint != null && s.mTint.isStateful());
71012b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    }
71112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
71212b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette    @Override
71352b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws XmlPullParserException, IOException {
71552b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        super.inflate(r, parser, attrs, theme);
71652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7170cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.BitmapDrawable);
7180cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        updateStateFromTypedArray(a);
71906318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette        verifyState(a);
72052b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        a.recycle();
72152b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    }
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
72352b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    /**
72406318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette     * Ensures all required attributes are set.
72506318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette     *
72606318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette     * @throws XmlPullParserException if any required attributes are missing
72706318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette     */
72806318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette    private void verifyState(TypedArray a) throws XmlPullParserException {
72906318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette        final BitmapState state = mBitmapState;
73006318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette        if (state.mBitmap == null) {
73106318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette            throw new XmlPullParserException(a.getPositionDescription() +
73206318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette                    ": <bitmap> requires a valid src attribute");
73306318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette        }
73406318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette    }
73506318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette
73606318a0869b9f214bc97cabf1d2b6854acb6431bAlan Viverette    /**
7370cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * Updates the constant state from the values in the typed array.
73852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette     */
7390cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
74052b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        final Resources r = a.getResources();
74112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette        final BitmapState state = mBitmapState;
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7438e5e11b99fac942122ee2d6cdd30af51564861aeAlan Viverette        // Account for any configuration changes.
7448e5e11b99fac942122ee2d6cdd30af51564861aeAlan Viverette        state.mChangingConfigurations |= a.getChangingConfigurations();
7458e5e11b99fac942122ee2d6cdd30af51564861aeAlan Viverette
74652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        // Extract the theme attributes, if any.
7478e5e11b99fac942122ee2d6cdd30af51564861aeAlan Viverette        state.mThemeAttrs = a.extractThemeAttrs();
74852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7490cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final int srcResId = a.getResourceId(R.styleable.BitmapDrawable_src, 0);
7500cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (srcResId != 0) {
7510cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            final Bitmap bitmap = BitmapFactory.decodeResource(r, srcResId);
75252b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            if (bitmap == null) {
75352b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette                throw new XmlPullParserException(a.getPositionDescription() +
75452b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette                        ": <bitmap> requires a valid src attribute");
75552b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            }
7560cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette
75752b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            state.mBitmap = bitmap;
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
75952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7600cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        state.mTargetDensity = r.getDisplayMetrics().densityDpi;
76152b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7620cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final boolean defMipMap = state.mBitmap != null ? state.mBitmap.hasMipMap() : false;
7630cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        setMipMap(a.getBoolean(R.styleable.BitmapDrawable_mipMap, defMipMap));
76452b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7650cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        state.mAutoMirrored = a.getBoolean(
7660cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette                R.styleable.BitmapDrawable_autoMirrored, state.mAutoMirrored);
7670cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        state.mBaseAlpha = a.getFloat(R.styleable.BitmapDrawable_alpha, state.mBaseAlpha);
76852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7690cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final int tintMode = a.getInt(R.styleable.BitmapDrawable_tintMode, -1);
7700cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (tintMode != -1) {
7710cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
77252b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        }
77352b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7740cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final ColorStateList tint = a.getColorStateList(R.styleable.BitmapDrawable_tint);
7750cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (tint != null) {
7760cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            state.mTint = tint;
77752b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        }
77852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
77952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        final Paint paint = mBitmapState.mPaint;
7800cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        paint.setAntiAlias(a.getBoolean(
7810cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette                R.styleable.BitmapDrawable_antialias, paint.isAntiAlias()));
7820cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        paint.setFilterBitmap(a.getBoolean(
7830cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette                R.styleable.BitmapDrawable_filter, paint.isFilterBitmap()));
7840cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        paint.setDither(a.getBoolean(R.styleable.BitmapDrawable_dither, paint.isDither()));
78552b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7860cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        setGravity(a.getInt(R.styleable.BitmapDrawable_gravity, state.mGravity));
78752b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
7880cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final int tileMode = a.getInt(R.styleable.BitmapDrawable_tileMode, TILE_MODE_UNDEFINED);
7890cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (tileMode != TILE_MODE_UNDEFINED) {
79022594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette            final Shader.TileMode mode = parseTileMode(tileMode);
79122594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette            setTileModeXY(mode, mode);
79222594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette        }
79322594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette
79422594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette        final int tileModeX = a.getInt(R.styleable.BitmapDrawable_tileModeX, TILE_MODE_UNDEFINED);
79522594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette        if (tileModeX != TILE_MODE_UNDEFINED) {
79622594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette            setTileModeX(parseTileMode(tileModeX));
79722594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette        }
79822594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette
79922594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette        final int tileModeY = a.getInt(R.styleable.BitmapDrawable_tileModeY, TILE_MODE_UNDEFINED);
80022594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette        if (tileModeY != TILE_MODE_UNDEFINED) {
80122594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette            setTileModeY(parseTileMode(tileModeY));
80252b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        }
8030cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette
8040cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        // Update local properties.
8050cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        initializeWithState(state, r);
80652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    }
80752b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
80852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    @Override
80952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    public void applyTheme(Theme t) {
81052b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        super.applyTheme(t);
81152b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
81252b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        final BitmapState state = mBitmapState;
8130cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        if (state == null || state.mThemeAttrs == null) {
8140cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            return;
81552b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        }
81652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
8170cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.BitmapDrawable);
8180cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        try {
81952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            updateStateFromTypedArray(a);
8200cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        } catch (XmlPullParserException e) {
8210cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            throw new RuntimeException(e);
8220cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        } finally {
82352b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            a.recycle();
82452b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        }
82552b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    }
82652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
82722594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette    private static Shader.TileMode parseTileMode(int tileMode) {
82852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        switch (tileMode) {
8290cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            case TILE_MODE_CLAMP:
83022594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette                return Shader.TileMode.CLAMP;
8310cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            case TILE_MODE_REPEAT:
83222594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette                return Shader.TileMode.REPEAT;
8330cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            case TILE_MODE_MIRROR:
83422594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette                return Shader.TileMode.MIRROR;
83522594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette            default:
83622594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette                return null;
83752b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        }
83852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    }
83952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
84052b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    @Override
84152b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    public boolean canApplyTheme() {
84252b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        return mBitmapState != null && mBitmapState.mThemeAttrs != null;
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getIntrinsicWidth() {
84711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        return mBitmapWidth;
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getIntrinsicHeight() {
85211ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        return mBitmapHeight;
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getOpacity() {
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mBitmapState.mGravity != Gravity.FILL) {
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return PixelFormat.TRANSLUCENT;
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8600cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette
8610cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final Bitmap bitmap = mBitmapState.mBitmap;
8620cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        return (bitmap == null || bitmap.hasAlpha() || mBitmapState.mPaint.getAlpha() < 255) ?
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final ConstantState getConstantState() {
8686efd2bad954e0e5bd74916a32f036a0f149dcd4dChristopher Lais        mBitmapState.mChangingConfigurations = getChangingConfigurations();
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmapState;
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final static class BitmapState extends ConstantState {
8730cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        final Paint mPaint;
8740cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette
8750cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        // Values loaded during inflation.
8760cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        int[] mThemeAttrs = null;
8770cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        Bitmap mBitmap = null;
8780cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        ColorStateList mTint = null;
879607bd848269fb802550e63aa61945790616f97a7Alan Viverette        Mode mTintMode = DEFAULT_TINT_MODE;
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int mGravity = Gravity.FILL;
881307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette        float mBaseAlpha = 1.0f;
882ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy        Shader.TileMode mTileModeX = null;
883ee0c116ab2bd5acdfe50db36441cf4784d3a10b4Romain Guy        Shader.TileMode mTileModeY = null;
88411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
8850cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        boolean mAutoMirrored = false;
8860cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette
8870cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        int mChangingConfigurations;
8882660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy        boolean mRebuildShader;
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BitmapState(Bitmap bitmap) {
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mBitmap = bitmap;
8920cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette            mPaint = new Paint(DEFAULT_PAINT_FLAGS);
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BitmapState(BitmapState bitmapState) {
896d9e788c4f0528e46db4a035cfac043736becb0d1Alan Viverette            mBitmap = bitmapState.mBitmap;
89712b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            mTint = bitmapState.mTint;
89812b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette            mTintMode = bitmapState.mTintMode;
89952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            mThemeAttrs = bitmapState.mThemeAttrs;
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mChangingConfigurations = bitmapState.mChangingConfigurations;
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mGravity = bitmapState.mGravity;
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTileModeX = bitmapState.mTileModeX;
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTileModeY = bitmapState.mTileModeY;
90411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn            mTargetDensity = bitmapState.mTargetDensity;
905307ad09228ebf70f1b456f5f00540c0126277850Alan Viverette            mBaseAlpha = bitmapState.mBaseAlpha;
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPaint = new Paint(bitmapState.mPaint);
9072660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy            mRebuildShader = bitmapState.mRebuildShader;
9083f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio            mAutoMirrored = bitmapState.mAutoMirrored;
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
91252b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        public boolean canApplyTheme() {
91352b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            return mThemeAttrs != null;
91452b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        }
91552b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
91652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette        @Override
917dad7d84c04c5954b63ea8bb58c52b2291f44b4dfJohn Reck        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
918dad7d84c04c5954b63ea8bb58c52b2291f44b4dfJohn Reck            if (isAtlasable(mBitmap) && atlasList.add(mBitmap)) {
919dad7d84c04c5954b63ea8bb58c52b2291f44b4dfJohn Reck                return mBitmap.getWidth() * mBitmap.getHeight();
920dad7d84c04c5954b63ea8bb58c52b2291f44b4dfJohn Reck            }
921dad7d84c04c5954b63ea8bb58c52b2291f44b4dfJohn Reck            return 0;
9223b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        }
9233b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
9243b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        @Override
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Drawable newDrawable() {
92617cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette            return new BitmapDrawable(this, null);
927c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        }
9282660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy
929c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        @Override
930c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        public Drawable newDrawable(Resources res) {
93117cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette            return new BitmapDrawable(this, res);
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9332660a3ec8564918a243b1b02e3652c514bc93bfcRomain Guy
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getChangingConfigurations() {
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mChangingConfigurations;
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9400cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette    /**
9410cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * The one constructor to rule them all. This is called by all public
9420cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     * constructors to set the state and initialize local properties.
9430cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette     */
94417cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette    private BitmapDrawable(BitmapState state, Resources res) {
94517cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette        mBitmapState = state;
94652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
94717cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette        initializeWithState(mBitmapState, res);
94852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    }
94912b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
95052b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    /**
95122594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette     * Initializes local dynamic properties from state. This should be called
95222594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette     * after significant state changes, e.g. from the One True Constructor and
95322594f097242d9de0a538a9b8142f77da9df7ebdAlan Viverette     * after inflating or applying a theme.
95452b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette     */
95552b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    private void initializeWithState(BitmapState state, Resources res) {
956c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        if (res != null) {
957c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            mTargetDensity = res.getDisplayMetrics().densityDpi;
958c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        } else {
959e42143aa575dcb8ab0616080b2e9b4614a1a4167Jozef BABJAK            mTargetDensity = state.mTargetDensity;
960c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        }
96112b97f5d2b15194ed6673c9838b13c8312157709Alan Viverette
9625adf8ee451085ed6106b7dbadc6d8dcd9d90722bAlan Viverette        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
9630cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette        computeBitmapSize();
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
966