Loading core/res/res/values/attrs.xml +7 −0 Original line number Diff line number Diff line Loading @@ -5018,6 +5018,12 @@ i <attr name="autoMirrored" format="boolean" /> </declare-styleable> <!-- Drawable class used to wrap other drawables. --> <declare-styleable name="DrawableWrapper"> <!-- The wrapped drawable. --> <attr name="drawable" /> </declare-styleable> <!-- Drawable used to render several states. Each state is represented by a child drawable. --> <declare-styleable name="StateListDrawable"> Loading Loading @@ -5385,6 +5391,7 @@ i <attr name="color" /> </declare-styleable> <!-- Drawable used to wrap and inset another drawable. --> <declare-styleable name="InsetDrawable"> <attr name="visible" /> <attr name="drawable" /> Loading graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java +50 −42 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ public class AnimatedRotateDrawable extends DrawableWrapper implements Animatabl * Creates a new animated rotating drawable with no wrapped drawable. */ public AnimatedRotateDrawable() { this(new AnimatedRotateState(null), null); this(new AnimatedRotateState(null, null), null); } @Override Loading Loading @@ -126,17 +126,43 @@ public class AnimatedRotateDrawable extends DrawableWrapper implements Animatabl @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimatedRotateDrawable); super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible); // Inflation will advance the XmlPullParser and AttributeSet. super.inflate(r, parser, attrs, theme); updateStateFromTypedArray(a); inflateChildDrawable(r, parser, attrs, theme); verifyRequiredAttributes(a); a.recycle(); updateLocalState(); } private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException { @Override public void applyTheme(@NonNull Theme t) { super.applyTheme(t); final AnimatedRotateState state = mState; if (state == null) { return; } if (state.mThemeAttrs != null) { final TypedArray a = t.resolveAttributes( state.mThemeAttrs, R.styleable.AnimatedRotateDrawable); try { updateStateFromTypedArray(a); verifyRequiredAttributes(a); } catch (XmlPullParserException e) { throw new RuntimeException(e); } finally { a.recycle(); } } updateLocalState(); } private void verifyRequiredAttributes(@NonNull TypedArray a) throws XmlPullParserException { // If we're not waiting on a theme, verify required attributes. if (getDrawable() == null && (mState.mThemeAttrs == null || mState.mThemeAttrs[R.styleable.AnimatedRotateDrawable_drawable] == 0)) { Loading @@ -146,11 +172,17 @@ public class AnimatedRotateDrawable extends DrawableWrapper implements Animatabl } } @Override void updateStateFromTypedArray(TypedArray a) { super.updateStateFromTypedArray(a); private void updateStateFromTypedArray(@NonNull TypedArray a) { final AnimatedRotateState state = mState; if (state == null) { return; } // Account for any configuration changes. state.mChangingConfigurations |= a.getChangingConfigurations(); // Extract the theme attributes, if any. state.mThemeAttrs = a.extractThemeAttrs(); if (a.hasValue(R.styleable.AnimatedRotateDrawable_pivotX)) { final TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX); Loading @@ -168,38 +200,6 @@ public class AnimatedRotateDrawable extends DrawableWrapper implements Animatabl R.styleable.AnimatedRotateDrawable_framesCount, state.mFramesCount)); setFramesDuration(a.getInt( R.styleable.AnimatedRotateDrawable_frameDuration, state.mFrameDuration)); final Drawable dr = a.getDrawable(R.styleable.AnimatedRotateDrawable_drawable); if (dr != null) { setDrawable(dr); } } @Override public void applyTheme(@Nullable Theme t) { final AnimatedRotateState state = mState; if (state == null) { return; } if (state.mThemeAttrs != null) { final TypedArray a = t.resolveAttributes( state.mThemeAttrs, R.styleable.AnimatedRotateDrawable); try { updateStateFromTypedArray(a); verifyRequiredAttributes(a); } catch (XmlPullParserException e) { throw new RuntimeException(e); } finally { a.recycle(); } } // The drawable may have changed as a result of applying the theme, so // apply the theme to the wrapped drawable last. super.applyTheme(t); updateLocalState(); } public void setFramesCount(int framesCount) { Loading @@ -211,7 +211,15 @@ public class AnimatedRotateDrawable extends DrawableWrapper implements Animatabl mState.mFrameDuration = framesDuration; } @Override DrawableWrapperState mutateConstantState() { mState = new AnimatedRotateState(mState, null); return mState; } static final class AnimatedRotateState extends DrawableWrapper.DrawableWrapperState { private int[] mThemeAttrs; boolean mPivotXRel = false; float mPivotX = 0; boolean mPivotYRel = false; Loading @@ -219,8 +227,8 @@ public class AnimatedRotateDrawable extends DrawableWrapper implements Animatabl int mFrameDuration = 150; int mFramesCount = 12; public AnimatedRotateState(AnimatedRotateState orig) { super(orig); public AnimatedRotateState(AnimatedRotateState orig, Resources res) { super(orig, res); if (orig != null) { mPivotXRel = orig.mPivotXRel; Loading graphics/java/android/graphics/drawable/ClipDrawable.java +48 −36 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import com.android.internal.R; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.Resources.Theme; Loading Loading @@ -59,7 +61,7 @@ public class ClipDrawable extends DrawableWrapper { private ClipState mState; ClipDrawable() { this(new ClipState(null), null); this(new ClipState(null, null), null); } /** Loading @@ -72,7 +74,7 @@ public class ClipDrawable extends DrawableWrapper { * {@link #VERTICAL} */ public ClipDrawable(Drawable drawable, int gravity, int orientation) { this(new ClipState(null), null); this(new ClipState(null, null), null); mState.mGravity = gravity; mState.mOrientation = orientation; Loading @@ -81,45 +83,23 @@ public class ClipDrawable extends DrawableWrapper { } @Override public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ClipDrawable); // Inflation will advance the XmlPullParser and AttributeSet. super.inflate(r, parser, attrs, theme); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ClipDrawable); updateStateFromTypedArray(a); inflateChildDrawable(r, parser, attrs, theme); verifyRequiredAttributes(a); a.recycle(); } private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException { // If we're not waiting on a theme, verify required attributes. if (getDrawable() == null && (mState.mThemeAttrs == null || mState.mThemeAttrs[R.styleable.ClipDrawable_drawable] == 0)) { throw new XmlPullParserException(a.getPositionDescription() + ": <clip> tag requires a 'drawable' attribute or " + "child tag defining a drawable"); } } @Override void updateStateFromTypedArray(TypedArray a) { super.updateStateFromTypedArray(a); final ClipState state = mState; state.mOrientation = a.getInt( R.styleable.ClipDrawable_clipOrientation, state.mOrientation); state.mGravity = a.getInt( R.styleable.ClipDrawable_gravity, state.mGravity); final Drawable dr = a.getDrawable(R.styleable.ClipDrawable_drawable); if (dr != null) { setDrawable(dr); } } public void applyTheme(@NonNull Theme t) { super.applyTheme(t); @Override public void applyTheme(Theme t) { final ClipState state = mState; if (state == null) { return; Loading @@ -136,10 +116,34 @@ public class ClipDrawable extends DrawableWrapper { a.recycle(); } } } // The drawable may have changed as a result of applying the theme, so // apply the theme to the wrapped drawable last. super.applyTheme(t); private void verifyRequiredAttributes(@NonNull TypedArray a) throws XmlPullParserException { // If we're not waiting on a theme, verify required attributes. if (getDrawable() == null && (mState.mThemeAttrs == null || mState.mThemeAttrs[R.styleable.ClipDrawable_drawable] == 0)) { throw new XmlPullParserException(a.getPositionDescription() + ": <clip> tag requires a 'drawable' attribute or " + "child tag defining a drawable"); } } private void updateStateFromTypedArray(@NonNull TypedArray a) { final ClipState state = mState; if (state == null) { return; } // Account for any configuration changes. state.mChangingConfigurations |= a.getChangingConfigurations(); // Extract the theme attributes, if any. state.mThemeAttrs = a.extractThemeAttrs(); state.mOrientation = a.getInt( R.styleable.ClipDrawable_clipOrientation, state.mOrientation); state.mGravity = a.getInt( R.styleable.ClipDrawable_gravity, state.mGravity); } @Override Loading Loading @@ -200,12 +204,20 @@ public class ClipDrawable extends DrawableWrapper { } } @Override DrawableWrapperState mutateConstantState() { mState = new ClipState(mState, null); return mState; } static final class ClipState extends DrawableWrapper.DrawableWrapperState { private int[] mThemeAttrs; int mOrientation = HORIZONTAL; int mGravity = Gravity.LEFT; ClipState(ClipState orig) { super(orig); ClipState(ClipState orig, Resources res) { super(orig, res); if (orig != null) { mOrientation = orig.mOrientation; Loading graphics/java/android/graphics/drawable/Drawable.java +13 −15 Original line number Diff line number Diff line Loading @@ -55,6 +55,8 @@ import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.Collection; import com.android.internal.R; /** * A Drawable is a general abstraction for "something that can be drawn." Most * often you will deal with Drawable as the type of resource retrieved for Loading Loading @@ -791,8 +793,10 @@ public abstract class Drawable { /** * Applies the specified theme to this Drawable and its children. * * @param t the theme to apply */ public void applyTheme(@SuppressWarnings("unused") Theme t) { public void applyTheme(@NonNull @SuppressWarnings("unused") Theme t) { } public boolean canApplyTheme() { Loading Loading @@ -1177,8 +1181,8 @@ public abstract class Drawable { * * @see #inflate(Resources, XmlPullParser, AttributeSet, Theme) */ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException { public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs) throws XmlPullParserException, IOException { inflate(r, parser, attrs, null); } Loading @@ -1192,17 +1196,11 @@ public abstract class Drawable { * @throws XmlPullParserException * @throws IOException */ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { final TypedArray a; if (theme != null) { a = theme.obtainStyledAttributes( attrs, com.android.internal.R.styleable.Drawable, 0, 0); } else { a = r.obtainAttributes(attrs, com.android.internal.R.styleable.Drawable); } inflateWithAttributes(r, parser, a, com.android.internal.R.styleable.Drawable_visible); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.Drawable); mVisible = a.getBoolean(R.styleable.Drawable_visible, mVisible); a.recycle(); } Loading @@ -1212,8 +1210,8 @@ public abstract class Drawable { * @throws XmlPullParserException * @throws IOException */ void inflateWithAttributes(Resources r, XmlPullParser parser, TypedArray attrs, int visibleAttr) throws XmlPullParserException, IOException { void inflateWithAttributes(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull TypedArray attrs, int visibleAttr) throws XmlPullParserException, IOException { mVisible = attrs.getBoolean(visibleAttr, mVisible); } Loading graphics/java/android/graphics/drawable/DrawableWrapper.java +110 −14 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.graphics.drawable; import com.android.internal.R; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; Loading @@ -23,6 +25,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; Loading @@ -33,6 +36,7 @@ import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.Rect; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.View; import java.io.IOException; Loading Loading @@ -112,32 +116,79 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb return mDrawable; } void updateStateFromTypedArray(TypedArray a) { @Override public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { super.inflate(r, parser, attrs, theme); final DrawableWrapperState state = mState; if (state == null) { return; } // Account for any configuration changes. state.mChangingConfigurations |= a.getChangingConfigurations(); // The density may have changed since the last update. This will // apply scaling to any existing constant state properties. final int densityDpi = r.getDisplayMetrics().densityDpi; final int targetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; state.setDensity(targetDensity); // Extract the theme attributes, if any. state.mThemeAttrs = a.extractThemeAttrs(); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.DrawableWrapper); updateStateFromTypedArray(a); a.recycle(); // TODO: Consider using R.styleable.DrawableWrapper_drawable inflateChildDrawable(r, parser, attrs, theme); } @Override public void applyTheme(Resources.Theme t) { public void applyTheme(@NonNull Theme t) { super.applyTheme(t); // If we load the drawable later as part of updating from the typed // array, it will already be themed correctly. So, we can theme the // local drawable first. if (mDrawable != null && mDrawable.canApplyTheme()) { mDrawable.applyTheme(t); } final DrawableWrapperState state = mState; if (state == null) { return; } if (mDrawable != null && mDrawable.canApplyTheme()) { mDrawable.applyTheme(t); final int densityDpi = t.getResources().getDisplayMetrics().densityDpi; final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; state.setDensity(density); if (state.mThemeAttrs != null) { final TypedArray a = t.resolveAttributes( state.mThemeAttrs, R.styleable.DrawableWrapper); updateStateFromTypedArray(a); a.recycle(); } } /** * Updates constant state properties from the provided typed array. * <p> * Implementing subclasses should call through to the super method first. * * @param a the typed array rom which properties should be read */ private void updateStateFromTypedArray(@NonNull TypedArray a) { final DrawableWrapperState state = mState; if (state == null) { return; } // Account for any configuration changes. state.mChangingConfigurations |= a.getChangingConfigurations(); // Extract the theme attributes, if any. state.mThemeAttrs = a.extractThemeAttrs(); if (a.hasValueOrEmpty(R.styleable.DrawableWrapper_drawable)) { setDrawable(a.getDrawable(R.styleable.DrawableWrapper_drawable)); } } Loading Loading @@ -371,8 +422,9 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb * child element will take precedence over any other child elements or * explicit drawable attribute. */ void inflateChildDrawable(Resources r, XmlPullParser parser, AttributeSet attrs, Resources.Theme theme) throws XmlPullParserException, IOException { private void inflateChildDrawable(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { // Seek to the first child element. Drawable dr = null; int type; Loading @@ -390,17 +442,61 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb } abstract static class DrawableWrapperState extends Drawable.ConstantState { int[] mThemeAttrs; private int[] mThemeAttrs; int mChangingConfigurations; int mDensity = DisplayMetrics.DENSITY_DEFAULT; Drawable.ConstantState mDrawableState; DrawableWrapperState(DrawableWrapperState orig) { DrawableWrapperState(@Nullable DrawableWrapperState orig, @Nullable Resources res) { if (orig != null) { mThemeAttrs = orig.mThemeAttrs; mChangingConfigurations = orig.mChangingConfigurations; mDrawableState = orig.mDrawableState; } final int density; if (res != null) { density = res.getDisplayMetrics().densityDpi; } else if (orig != null) { density = orig.mDensity; } else { density = 0; } mDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density; } /** * Sets the constant state density. * <p> * If the density has been previously set, dispatches the change to * subclasses so that density-dependent properties may be scaled as * necessary. * * @param targetDensity the new constant state density */ public final void setDensity(int targetDensity) { if (mDensity != targetDensity) { final int sourceDensity = mDensity; mDensity = targetDensity; onDensityChanged(sourceDensity, targetDensity); } } /** * Called when the constant state density changes. * <p> * Subclasses with density-dependent constant state properties should * override this method and scale their properties as necessary. * * @param sourceDensity the previous constant state density * @param targetDensity the new constant state density */ void onDensityChanged(int sourceDensity, int targetDensity) { // Stub method. } @Override Loading @@ -425,7 +521,7 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb } @Override public abstract Drawable newDrawable(Resources res); public abstract Drawable newDrawable(@Nullable Resources res); @Override public int getChangingConfigurations() { Loading Loading
core/res/res/values/attrs.xml +7 −0 Original line number Diff line number Diff line Loading @@ -5018,6 +5018,12 @@ i <attr name="autoMirrored" format="boolean" /> </declare-styleable> <!-- Drawable class used to wrap other drawables. --> <declare-styleable name="DrawableWrapper"> <!-- The wrapped drawable. --> <attr name="drawable" /> </declare-styleable> <!-- Drawable used to render several states. Each state is represented by a child drawable. --> <declare-styleable name="StateListDrawable"> Loading Loading @@ -5385,6 +5391,7 @@ i <attr name="color" /> </declare-styleable> <!-- Drawable used to wrap and inset another drawable. --> <declare-styleable name="InsetDrawable"> <attr name="visible" /> <attr name="drawable" /> Loading
graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java +50 −42 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ public class AnimatedRotateDrawable extends DrawableWrapper implements Animatabl * Creates a new animated rotating drawable with no wrapped drawable. */ public AnimatedRotateDrawable() { this(new AnimatedRotateState(null), null); this(new AnimatedRotateState(null, null), null); } @Override Loading Loading @@ -126,17 +126,43 @@ public class AnimatedRotateDrawable extends DrawableWrapper implements Animatabl @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimatedRotateDrawable); super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible); // Inflation will advance the XmlPullParser and AttributeSet. super.inflate(r, parser, attrs, theme); updateStateFromTypedArray(a); inflateChildDrawable(r, parser, attrs, theme); verifyRequiredAttributes(a); a.recycle(); updateLocalState(); } private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException { @Override public void applyTheme(@NonNull Theme t) { super.applyTheme(t); final AnimatedRotateState state = mState; if (state == null) { return; } if (state.mThemeAttrs != null) { final TypedArray a = t.resolveAttributes( state.mThemeAttrs, R.styleable.AnimatedRotateDrawable); try { updateStateFromTypedArray(a); verifyRequiredAttributes(a); } catch (XmlPullParserException e) { throw new RuntimeException(e); } finally { a.recycle(); } } updateLocalState(); } private void verifyRequiredAttributes(@NonNull TypedArray a) throws XmlPullParserException { // If we're not waiting on a theme, verify required attributes. if (getDrawable() == null && (mState.mThemeAttrs == null || mState.mThemeAttrs[R.styleable.AnimatedRotateDrawable_drawable] == 0)) { Loading @@ -146,11 +172,17 @@ public class AnimatedRotateDrawable extends DrawableWrapper implements Animatabl } } @Override void updateStateFromTypedArray(TypedArray a) { super.updateStateFromTypedArray(a); private void updateStateFromTypedArray(@NonNull TypedArray a) { final AnimatedRotateState state = mState; if (state == null) { return; } // Account for any configuration changes. state.mChangingConfigurations |= a.getChangingConfigurations(); // Extract the theme attributes, if any. state.mThemeAttrs = a.extractThemeAttrs(); if (a.hasValue(R.styleable.AnimatedRotateDrawable_pivotX)) { final TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX); Loading @@ -168,38 +200,6 @@ public class AnimatedRotateDrawable extends DrawableWrapper implements Animatabl R.styleable.AnimatedRotateDrawable_framesCount, state.mFramesCount)); setFramesDuration(a.getInt( R.styleable.AnimatedRotateDrawable_frameDuration, state.mFrameDuration)); final Drawable dr = a.getDrawable(R.styleable.AnimatedRotateDrawable_drawable); if (dr != null) { setDrawable(dr); } } @Override public void applyTheme(@Nullable Theme t) { final AnimatedRotateState state = mState; if (state == null) { return; } if (state.mThemeAttrs != null) { final TypedArray a = t.resolveAttributes( state.mThemeAttrs, R.styleable.AnimatedRotateDrawable); try { updateStateFromTypedArray(a); verifyRequiredAttributes(a); } catch (XmlPullParserException e) { throw new RuntimeException(e); } finally { a.recycle(); } } // The drawable may have changed as a result of applying the theme, so // apply the theme to the wrapped drawable last. super.applyTheme(t); updateLocalState(); } public void setFramesCount(int framesCount) { Loading @@ -211,7 +211,15 @@ public class AnimatedRotateDrawable extends DrawableWrapper implements Animatabl mState.mFrameDuration = framesDuration; } @Override DrawableWrapperState mutateConstantState() { mState = new AnimatedRotateState(mState, null); return mState; } static final class AnimatedRotateState extends DrawableWrapper.DrawableWrapperState { private int[] mThemeAttrs; boolean mPivotXRel = false; float mPivotX = 0; boolean mPivotYRel = false; Loading @@ -219,8 +227,8 @@ public class AnimatedRotateDrawable extends DrawableWrapper implements Animatabl int mFrameDuration = 150; int mFramesCount = 12; public AnimatedRotateState(AnimatedRotateState orig) { super(orig); public AnimatedRotateState(AnimatedRotateState orig, Resources res) { super(orig, res); if (orig != null) { mPivotXRel = orig.mPivotXRel; Loading
graphics/java/android/graphics/drawable/ClipDrawable.java +48 −36 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import com.android.internal.R; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.Resources.Theme; Loading Loading @@ -59,7 +61,7 @@ public class ClipDrawable extends DrawableWrapper { private ClipState mState; ClipDrawable() { this(new ClipState(null), null); this(new ClipState(null, null), null); } /** Loading @@ -72,7 +74,7 @@ public class ClipDrawable extends DrawableWrapper { * {@link #VERTICAL} */ public ClipDrawable(Drawable drawable, int gravity, int orientation) { this(new ClipState(null), null); this(new ClipState(null, null), null); mState.mGravity = gravity; mState.mOrientation = orientation; Loading @@ -81,45 +83,23 @@ public class ClipDrawable extends DrawableWrapper { } @Override public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ClipDrawable); // Inflation will advance the XmlPullParser and AttributeSet. super.inflate(r, parser, attrs, theme); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ClipDrawable); updateStateFromTypedArray(a); inflateChildDrawable(r, parser, attrs, theme); verifyRequiredAttributes(a); a.recycle(); } private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException { // If we're not waiting on a theme, verify required attributes. if (getDrawable() == null && (mState.mThemeAttrs == null || mState.mThemeAttrs[R.styleable.ClipDrawable_drawable] == 0)) { throw new XmlPullParserException(a.getPositionDescription() + ": <clip> tag requires a 'drawable' attribute or " + "child tag defining a drawable"); } } @Override void updateStateFromTypedArray(TypedArray a) { super.updateStateFromTypedArray(a); final ClipState state = mState; state.mOrientation = a.getInt( R.styleable.ClipDrawable_clipOrientation, state.mOrientation); state.mGravity = a.getInt( R.styleable.ClipDrawable_gravity, state.mGravity); final Drawable dr = a.getDrawable(R.styleable.ClipDrawable_drawable); if (dr != null) { setDrawable(dr); } } public void applyTheme(@NonNull Theme t) { super.applyTheme(t); @Override public void applyTheme(Theme t) { final ClipState state = mState; if (state == null) { return; Loading @@ -136,10 +116,34 @@ public class ClipDrawable extends DrawableWrapper { a.recycle(); } } } // The drawable may have changed as a result of applying the theme, so // apply the theme to the wrapped drawable last. super.applyTheme(t); private void verifyRequiredAttributes(@NonNull TypedArray a) throws XmlPullParserException { // If we're not waiting on a theme, verify required attributes. if (getDrawable() == null && (mState.mThemeAttrs == null || mState.mThemeAttrs[R.styleable.ClipDrawable_drawable] == 0)) { throw new XmlPullParserException(a.getPositionDescription() + ": <clip> tag requires a 'drawable' attribute or " + "child tag defining a drawable"); } } private void updateStateFromTypedArray(@NonNull TypedArray a) { final ClipState state = mState; if (state == null) { return; } // Account for any configuration changes. state.mChangingConfigurations |= a.getChangingConfigurations(); // Extract the theme attributes, if any. state.mThemeAttrs = a.extractThemeAttrs(); state.mOrientation = a.getInt( R.styleable.ClipDrawable_clipOrientation, state.mOrientation); state.mGravity = a.getInt( R.styleable.ClipDrawable_gravity, state.mGravity); } @Override Loading Loading @@ -200,12 +204,20 @@ public class ClipDrawable extends DrawableWrapper { } } @Override DrawableWrapperState mutateConstantState() { mState = new ClipState(mState, null); return mState; } static final class ClipState extends DrawableWrapper.DrawableWrapperState { private int[] mThemeAttrs; int mOrientation = HORIZONTAL; int mGravity = Gravity.LEFT; ClipState(ClipState orig) { super(orig); ClipState(ClipState orig, Resources res) { super(orig, res); if (orig != null) { mOrientation = orig.mOrientation; Loading
graphics/java/android/graphics/drawable/Drawable.java +13 −15 Original line number Diff line number Diff line Loading @@ -55,6 +55,8 @@ import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.Collection; import com.android.internal.R; /** * A Drawable is a general abstraction for "something that can be drawn." Most * often you will deal with Drawable as the type of resource retrieved for Loading Loading @@ -791,8 +793,10 @@ public abstract class Drawable { /** * Applies the specified theme to this Drawable and its children. * * @param t the theme to apply */ public void applyTheme(@SuppressWarnings("unused") Theme t) { public void applyTheme(@NonNull @SuppressWarnings("unused") Theme t) { } public boolean canApplyTheme() { Loading Loading @@ -1177,8 +1181,8 @@ public abstract class Drawable { * * @see #inflate(Resources, XmlPullParser, AttributeSet, Theme) */ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException { public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs) throws XmlPullParserException, IOException { inflate(r, parser, attrs, null); } Loading @@ -1192,17 +1196,11 @@ public abstract class Drawable { * @throws XmlPullParserException * @throws IOException */ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { final TypedArray a; if (theme != null) { a = theme.obtainStyledAttributes( attrs, com.android.internal.R.styleable.Drawable, 0, 0); } else { a = r.obtainAttributes(attrs, com.android.internal.R.styleable.Drawable); } inflateWithAttributes(r, parser, a, com.android.internal.R.styleable.Drawable_visible); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.Drawable); mVisible = a.getBoolean(R.styleable.Drawable_visible, mVisible); a.recycle(); } Loading @@ -1212,8 +1210,8 @@ public abstract class Drawable { * @throws XmlPullParserException * @throws IOException */ void inflateWithAttributes(Resources r, XmlPullParser parser, TypedArray attrs, int visibleAttr) throws XmlPullParserException, IOException { void inflateWithAttributes(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull TypedArray attrs, int visibleAttr) throws XmlPullParserException, IOException { mVisible = attrs.getBoolean(visibleAttr, mVisible); } Loading
graphics/java/android/graphics/drawable/DrawableWrapper.java +110 −14 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.graphics.drawable; import com.android.internal.R; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; Loading @@ -23,6 +25,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; Loading @@ -33,6 +36,7 @@ import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.Rect; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.View; import java.io.IOException; Loading Loading @@ -112,32 +116,79 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb return mDrawable; } void updateStateFromTypedArray(TypedArray a) { @Override public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { super.inflate(r, parser, attrs, theme); final DrawableWrapperState state = mState; if (state == null) { return; } // Account for any configuration changes. state.mChangingConfigurations |= a.getChangingConfigurations(); // The density may have changed since the last update. This will // apply scaling to any existing constant state properties. final int densityDpi = r.getDisplayMetrics().densityDpi; final int targetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; state.setDensity(targetDensity); // Extract the theme attributes, if any. state.mThemeAttrs = a.extractThemeAttrs(); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.DrawableWrapper); updateStateFromTypedArray(a); a.recycle(); // TODO: Consider using R.styleable.DrawableWrapper_drawable inflateChildDrawable(r, parser, attrs, theme); } @Override public void applyTheme(Resources.Theme t) { public void applyTheme(@NonNull Theme t) { super.applyTheme(t); // If we load the drawable later as part of updating from the typed // array, it will already be themed correctly. So, we can theme the // local drawable first. if (mDrawable != null && mDrawable.canApplyTheme()) { mDrawable.applyTheme(t); } final DrawableWrapperState state = mState; if (state == null) { return; } if (mDrawable != null && mDrawable.canApplyTheme()) { mDrawable.applyTheme(t); final int densityDpi = t.getResources().getDisplayMetrics().densityDpi; final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; state.setDensity(density); if (state.mThemeAttrs != null) { final TypedArray a = t.resolveAttributes( state.mThemeAttrs, R.styleable.DrawableWrapper); updateStateFromTypedArray(a); a.recycle(); } } /** * Updates constant state properties from the provided typed array. * <p> * Implementing subclasses should call through to the super method first. * * @param a the typed array rom which properties should be read */ private void updateStateFromTypedArray(@NonNull TypedArray a) { final DrawableWrapperState state = mState; if (state == null) { return; } // Account for any configuration changes. state.mChangingConfigurations |= a.getChangingConfigurations(); // Extract the theme attributes, if any. state.mThemeAttrs = a.extractThemeAttrs(); if (a.hasValueOrEmpty(R.styleable.DrawableWrapper_drawable)) { setDrawable(a.getDrawable(R.styleable.DrawableWrapper_drawable)); } } Loading Loading @@ -371,8 +422,9 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb * child element will take precedence over any other child elements or * explicit drawable attribute. */ void inflateChildDrawable(Resources r, XmlPullParser parser, AttributeSet attrs, Resources.Theme theme) throws XmlPullParserException, IOException { private void inflateChildDrawable(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { // Seek to the first child element. Drawable dr = null; int type; Loading @@ -390,17 +442,61 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb } abstract static class DrawableWrapperState extends Drawable.ConstantState { int[] mThemeAttrs; private int[] mThemeAttrs; int mChangingConfigurations; int mDensity = DisplayMetrics.DENSITY_DEFAULT; Drawable.ConstantState mDrawableState; DrawableWrapperState(DrawableWrapperState orig) { DrawableWrapperState(@Nullable DrawableWrapperState orig, @Nullable Resources res) { if (orig != null) { mThemeAttrs = orig.mThemeAttrs; mChangingConfigurations = orig.mChangingConfigurations; mDrawableState = orig.mDrawableState; } final int density; if (res != null) { density = res.getDisplayMetrics().densityDpi; } else if (orig != null) { density = orig.mDensity; } else { density = 0; } mDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density; } /** * Sets the constant state density. * <p> * If the density has been previously set, dispatches the change to * subclasses so that density-dependent properties may be scaled as * necessary. * * @param targetDensity the new constant state density */ public final void setDensity(int targetDensity) { if (mDensity != targetDensity) { final int sourceDensity = mDensity; mDensity = targetDensity; onDensityChanged(sourceDensity, targetDensity); } } /** * Called when the constant state density changes. * <p> * Subclasses with density-dependent constant state properties should * override this method and scale their properties as necessary. * * @param sourceDensity the previous constant state density * @param targetDensity the new constant state density */ void onDensityChanged(int sourceDensity, int targetDensity) { // Stub method. } @Override Loading @@ -425,7 +521,7 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb } @Override public abstract Drawable newDrawable(Resources res); public abstract Drawable newDrawable(@Nullable Resources res); @Override public int getChangingConfigurations() { Loading