19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 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
198e5e11b99fac942122ee2d6cdd30af51564861aeAlan Viveretteimport com.android.internal.R;
208e5e11b99fac942122ee2d6cdd30af51564861aeAlan Viverette
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParser;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParserException;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24a12962207155305da44b5a1b8fb9acaed358c14cAlan Viveretteimport android.annotation.NonNull;
257e3ede288926bdfb79b1571fed74cad614935821Alan Viveretteimport android.annotation.Nullable;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources;
2752b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viveretteimport android.content.res.Resources.Theme;
28a12962207155305da44b5a1b8fb9acaed358c14cAlan Viveretteimport android.content.res.TypedArray;
297e3ede288926bdfb79b1571fed74cad614935821Alan Viveretteimport android.graphics.Bitmap;
300bece71ee24f75967b86de47cae07e6fc04b4b36Alan Viveretteimport android.graphics.Insets;
310bece71ee24f75967b86de47cae07e6fc04b4b36Alan Viveretteimport android.graphics.Outline;
326dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viveretteimport android.graphics.PixelFormat;
330bece71ee24f75967b86de47cae07e6fc04b4b36Alan Viveretteimport android.graphics.Rect;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
357e3ede288926bdfb79b1571fed74cad614935821Alan Viveretteimport android.util.DisplayMetrics;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A Drawable that insets another Drawable by a specified distance.
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is used when a View needs a background that is smaller than
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the View's actual bounds.
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
44dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * <p>It can be defined in an XML file with the <code>&lt;inset></code> element. For more
45dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * information, see the guide to <a
46dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#InsetDrawable_visible
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#InsetDrawable_drawable
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#InsetDrawable_insetLeft
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#InsetDrawable_insetRight
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#InsetDrawable_insetTop
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#InsetDrawable_insetBottom
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
55a12962207155305da44b5a1b8fb9acaed358c14cAlan Viverettepublic class InsetDrawable extends DrawableWrapper {
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Rect mTmpRect = new Rect();
578e5e11b99fac942122ee2d6cdd30af51564861aeAlan Viverette
58f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette    private InsetState mState;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
60f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette    /**
61f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     * No-arg constructor used by drawable inflation.
62f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     */
63f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette    InsetDrawable() {
647e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        this(new InsetState(null, null), null);
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
67f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette    /**
68f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     * Creates a new inset drawable with the specified inset.
69f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     *
70f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     * @param drawable The drawable to inset.
71f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     * @param inset Inset in pixels around the drawable.
72f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     */
737e3ede288926bdfb79b1571fed74cad614935821Alan Viverette    public InsetDrawable(@Nullable Drawable drawable, int inset) {
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(drawable, inset, inset, inset, inset);
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
77f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette    /**
78f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     * Creates a new inset drawable with the specified insets.
79f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     *
80f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     * @param drawable The drawable to inset.
81f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     * @param insetLeft Left inset in pixels.
82f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     * @param insetTop Top inset in pixels.
83f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     * @param insetRight Right inset in pixels.
84f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     * @param insetBottom Bottom inset in pixels.
85f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     */
867e3ede288926bdfb79b1571fed74cad614935821Alan Viverette    public InsetDrawable(@Nullable Drawable drawable, int insetLeft, int insetTop,
877e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            int insetRight, int insetBottom) {
887e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        this(new InsetState(null, null), null);
89b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
90d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        mState.mInsetLeft = insetLeft;
91d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        mState.mInsetTop = insetTop;
92d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        mState.mInsetRight = insetRight;
93d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        mState.mInsetBottom = insetBottom;
94b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
95a12962207155305da44b5a1b8fb9acaed358c14cAlan Viverette        setDrawable(drawable);
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9752b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette
9852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    @Override
997e3ede288926bdfb79b1571fed74cad614935821Alan Viverette    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
1007e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            @NonNull AttributeSet attrs, @Nullable Theme theme)
10152b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette            throws XmlPullParserException, IOException {
1027e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.InsetDrawable);
1037e3ede288926bdfb79b1571fed74cad614935821Alan Viverette
1047e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        // Inflation will advance the XmlPullParser and AttributeSet.
105a12962207155305da44b5a1b8fb9acaed358c14cAlan Viverette        super.inflate(r, parser, attrs, theme);
106014e14b242848eaa86a10562e1c494143a0149aaChet Haase
1078e5e11b99fac942122ee2d6cdd30af51564861aeAlan Viverette        updateStateFromTypedArray(a);
108d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        verifyRequiredAttributes(a);
109d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        a.recycle();
110d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    }
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
112a12962207155305da44b5a1b8fb9acaed358c14cAlan Viverette    @Override
1137e3ede288926bdfb79b1571fed74cad614935821Alan Viverette    public void applyTheme(@NonNull Theme t) {
1147e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        super.applyTheme(t);
1158e5e11b99fac942122ee2d6cdd30af51564861aeAlan Viverette
116d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        final InsetState state = mState;
11717cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette        if (state == null) {
1188e5e11b99fac942122ee2d6cdd30af51564861aeAlan Viverette            return;
1198e5e11b99fac942122ee2d6cdd30af51564861aeAlan Viverette        }
1208e5e11b99fac942122ee2d6cdd30af51564861aeAlan Viverette
12117cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette        if (state.mThemeAttrs != null) {
12217cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.InsetDrawable);
12317cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette            try {
12417cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette                updateStateFromTypedArray(a);
12517cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette                verifyRequiredAttributes(a);
12617cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette            } catch (XmlPullParserException e) {
127c078c605ab904b0e4a5d793cbeffd78c340f2816Alan Viverette                rethrowAsRuntimeException(e);
12817cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette            } finally {
12917cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette                a.recycle();
13017cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette            }
13117cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette        }
1327e3ede288926bdfb79b1571fed74cad614935821Alan Viverette    }
13317cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette
1347e3ede288926bdfb79b1571fed74cad614935821Alan Viverette    private void verifyRequiredAttributes(@NonNull TypedArray a) throws XmlPullParserException {
1357e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        // If we're not waiting on a theme, verify required attributes.
1367e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        if (getDrawable() == null && (mState.mThemeAttrs == null
1377e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                || mState.mThemeAttrs[R.styleable.InsetDrawable_drawable] == 0)) {
1387e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            throw new XmlPullParserException(a.getPositionDescription()
1397e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                    + ": <inset> tag requires a 'drawable' attribute or "
1407e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                    + "child tag defining a drawable");
1417e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        }
1427e3ede288926bdfb79b1571fed74cad614935821Alan Viverette    }
1437e3ede288926bdfb79b1571fed74cad614935821Alan Viverette
1447e3ede288926bdfb79b1571fed74cad614935821Alan Viverette    private void updateStateFromTypedArray(@NonNull TypedArray a) {
1457e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        final InsetState state = mState;
1467e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        if (state == null) {
1477e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            return;
1487e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        }
1497e3ede288926bdfb79b1571fed74cad614935821Alan Viverette
1507e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        // Account for any configuration changes.
1517e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        state.mChangingConfigurations |= a.getChangingConfigurations();
1527e3ede288926bdfb79b1571fed74cad614935821Alan Viverette
1537e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        // Extract the theme attributes, if any.
1547e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        state.mThemeAttrs = a.extractThemeAttrs();
1557e3ede288926bdfb79b1571fed74cad614935821Alan Viverette
1567e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        // Inset attribute may be overridden by more specific attributes.
1577e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        if (a.hasValue(R.styleable.InsetDrawable_inset)) {
1587e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            final int inset = a.getDimensionPixelOffset(R.styleable.InsetDrawable_inset, 0);
1597e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            state.mInsetLeft = inset;
1607e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            state.mInsetTop = inset;
1617e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            state.mInsetRight = inset;
1627e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            state.mInsetBottom = inset;
1637e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        }
1647e3ede288926bdfb79b1571fed74cad614935821Alan Viverette
1657e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        state.mInsetLeft = a.getDimensionPixelOffset(
1667e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                R.styleable.InsetDrawable_insetLeft, state.mInsetLeft);
1677e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        state.mInsetRight = a.getDimensionPixelOffset(
1687e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                R.styleable.InsetDrawable_insetRight, state.mInsetRight);
1697e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        state.mInsetTop = a.getDimensionPixelOffset(
1707e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                R.styleable.InsetDrawable_insetTop, state.mInsetTop);
1717e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        state.mInsetBottom = a.getDimensionPixelOffset(
1727e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                R.styleable.InsetDrawable_insetBottom, state.mInsetBottom);
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
174b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean getPadding(Rect padding) {
177a12962207155305da44b5a1b8fb9acaed358c14cAlan Viverette        final boolean pad = super.getPadding(padding);
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        padding.left += mState.mInsetLeft;
180d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        padding.right += mState.mInsetRight;
181d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        padding.top += mState.mInsetTop;
182d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        padding.bottom += mState.mInsetBottom;
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
184f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette        return pad || (mState.mInsetLeft | mState.mInsetRight
185f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette                | mState.mInsetTop | mState.mInsetBottom) != 0;
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
188c054966b719c8a7255f7cf4120cca5050acb68bdAlan Viverette    /** @hide */
189c054966b719c8a7255f7cf4120cca5050acb68bdAlan Viverette    @Override
190c054966b719c8a7255f7cf4120cca5050acb68bdAlan Viverette    public Insets getOpticalInsets() {
191c054966b719c8a7255f7cf4120cca5050acb68bdAlan Viverette        final Insets contentInsets = super.getOpticalInsets();
192d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        return Insets.of(contentInsets.left + mState.mInsetLeft,
193d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                contentInsets.top + mState.mInsetTop,
194d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                contentInsets.right + mState.mInsetRight,
195d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                contentInsets.bottom + mState.mInsetBottom);
196c054966b719c8a7255f7cf4120cca5050acb68bdAlan Viverette    }
197c054966b719c8a7255f7cf4120cca5050acb68bdAlan Viverette
19887980f9a7383fa4150f9c037ed34c37677f97f97Alan Viverette    @Override
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getOpacity() {
2006dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette        final InsetState state = mState;
201a12962207155305da44b5a1b8fb9acaed358c14cAlan Viverette        final int opacity = getDrawable().getOpacity();
2026dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette        if (opacity == PixelFormat.OPAQUE && (state.mInsetLeft > 0 || state.mInsetTop > 0
2036dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette                || state.mInsetRight > 0 || state.mInsetBottom > 0)) {
2046dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette            return PixelFormat.TRANSLUCENT;
2056dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette        }
2066dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette        return opacity;
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
208b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onBoundsChange(Rect bounds) {
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Rect r = mTmpRect;
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        r.set(bounds);
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
214d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        r.left += mState.mInsetLeft;
215d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        r.top += mState.mInsetTop;
216d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        r.right -= mState.mInsetRight;
217d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        r.bottom -= mState.mInsetBottom;
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
219a12962207155305da44b5a1b8fb9acaed358c14cAlan Viverette        // Apply inset bounds to the wrapped drawable.
220a12962207155305da44b5a1b8fb9acaed358c14cAlan Viverette        super.onBoundsChange(r);
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getIntrinsicWidth() {
22576165b2a4bc3b618bdfa9e4286d405892b68f122Alan Viverette        final int childWidth = getDrawable().getIntrinsicWidth();
22676165b2a4bc3b618bdfa9e4286d405892b68f122Alan Viverette        if (childWidth < 0) {
22776165b2a4bc3b618bdfa9e4286d405892b68f122Alan Viverette            return -1;
22876165b2a4bc3b618bdfa9e4286d405892b68f122Alan Viverette        }
22976165b2a4bc3b618bdfa9e4286d405892b68f122Alan Viverette        return childWidth + mState.mInsetLeft + mState.mInsetRight;
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getIntrinsicHeight() {
23476165b2a4bc3b618bdfa9e4286d405892b68f122Alan Viverette        final int childHeight = getDrawable().getIntrinsicHeight();
23576165b2a4bc3b618bdfa9e4286d405892b68f122Alan Viverette        if (childHeight < 0) {
23676165b2a4bc3b618bdfa9e4286d405892b68f122Alan Viverette            return -1;
23776165b2a4bc3b618bdfa9e4286d405892b68f122Alan Viverette        }
23876165b2a4bc3b618bdfa9e4286d405892b68f122Alan Viverette        return childHeight + mState.mInsetTop + mState.mInsetBottom;
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
24231ba192dd201df2cad96a8c503f730130ab0d80fChris Craik    public void getOutline(@NonNull Outline outline) {
243a12962207155305da44b5a1b8fb9acaed358c14cAlan Viverette        getDrawable().getOutline(outline);
2443e1585e05ddb0fd60033a5603e330b8ab1f69303Chris Craik    }
2453e1585e05ddb0fd60033a5603e330b8ab1f69303Chris Craik
2463e1585e05ddb0fd60033a5603e330b8ab1f69303Chris Craik    @Override
247a12962207155305da44b5a1b8fb9acaed358c14cAlan Viverette    DrawableWrapperState mutateConstantState() {
2487e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        mState = new InsetState(mState, null);
249a12962207155305da44b5a1b8fb9acaed358c14cAlan Viverette        return mState;
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
252a12962207155305da44b5a1b8fb9acaed358c14cAlan Viverette    static final class InsetState extends DrawableWrapper.DrawableWrapperState {
2537e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        private int[] mThemeAttrs;
2547e3ede288926bdfb79b1571fed74cad614935821Alan Viverette
255d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        int mInsetLeft = 0;
256d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        int mInsetTop = 0;
257d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        int mInsetRight = 0;
258d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        int mInsetBottom = 0;
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2607e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        InsetState(@Nullable InsetState orig, @Nullable Resources res) {
2617e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            super(orig, res);
262a12962207155305da44b5a1b8fb9acaed358c14cAlan Viverette
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (orig != null) {
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mInsetLeft = orig.mInsetLeft;
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mInsetTop = orig.mInsetTop;
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mInsetRight = orig.mInsetRight;
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mInsetBottom = orig.mInsetBottom;
2687e3ede288926bdfb79b1571fed74cad614935821Alan Viverette
2697e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                if (orig.mDensity != mDensity) {
2707e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                    applyDensityScaling(orig.mDensity, mDensity);
2717e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                }
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2767e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        void onDensityChanged(int sourceDensity, int targetDensity) {
2777e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            super.onDensityChanged(sourceDensity, targetDensity);
2787e3ede288926bdfb79b1571fed74cad614935821Alan Viverette
2797e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            applyDensityScaling(sourceDensity, targetDensity);
2807e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        }
2817e3ede288926bdfb79b1571fed74cad614935821Alan Viverette
2827e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        /**
2837e3ede288926bdfb79b1571fed74cad614935821Alan Viverette         * Called when the constant state density changes to scale
2847e3ede288926bdfb79b1571fed74cad614935821Alan Viverette         * density-dependent properties specific to insets.
2857e3ede288926bdfb79b1571fed74cad614935821Alan Viverette         *
2867e3ede288926bdfb79b1571fed74cad614935821Alan Viverette         * @param sourceDensity the previous constant state density
2877e3ede288926bdfb79b1571fed74cad614935821Alan Viverette         * @param targetDensity the new constant state density
2887e3ede288926bdfb79b1571fed74cad614935821Alan Viverette         */
2897e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        private void applyDensityScaling(int sourceDensity, int targetDensity) {
2907e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            mInsetLeft = Bitmap.scaleFromDensity(mInsetLeft, sourceDensity, targetDensity);
2917e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            mInsetTop = Bitmap.scaleFromDensity(mInsetTop, sourceDensity, targetDensity);
2927e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            mInsetRight = Bitmap.scaleFromDensity(mInsetRight, sourceDensity, targetDensity);
2937e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            mInsetBottom = Bitmap.scaleFromDensity(mInsetBottom, sourceDensity, targetDensity);
2947e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        }
2957e3ede288926bdfb79b1571fed74cad614935821Alan Viverette
2967e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        @Override
2977e3ede288926bdfb79b1571fed74cad614935821Alan Viverette        public Drawable newDrawable(@Nullable Resources res) {
2987e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            // If this drawable is being created for a different density,
2997e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            // just create a new constant state and call it a day.
3007e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            final InsetState state;
3017e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            if (res != null) {
3027e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                final int densityDpi = res.getDisplayMetrics().densityDpi;
3037e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
3047e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                if (density != mDensity) {
3057e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                    state = new InsetState(this, res);
3067e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                } else {
3077e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                    state = this;
3087e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                }
3097e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            } else {
3107e3ede288926bdfb79b1571fed74cad614935821Alan Viverette                state = this;
3117e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            }
3127e3ede288926bdfb79b1571fed74cad614935821Alan Viverette
3137e3ede288926bdfb79b1571fed74cad614935821Alan Viverette            return new InsetDrawable(state, res);
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
317f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette    /**
318f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     * The one constructor to rule them all. This is called by all public
319f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     * constructors to set the state and initialize local properties.
320f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette     */
3217e3ede288926bdfb79b1571fed74cad614935821Alan Viverette    private InsetDrawable(@NonNull InsetState state, @Nullable Resources res) {
322a12962207155305da44b5a1b8fb9acaed358c14cAlan Viverette        super(state, res);
323f0f7f8ceb5d1effd34fe2734f6493726bf01dd1cAlan Viverette
324a12962207155305da44b5a1b8fb9acaed358c14cAlan Viverette        mState = state;
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
328