diff options
8 files changed, 201 insertions, 71 deletions
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 408bee8a0223..b559604ea14e 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -815,14 +815,7 @@ public class Resources { */ public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme) throws NotFoundException { - final TypedValue value = obtainTempTypedValue(); - try { - final ResourcesImpl impl = mResourcesImpl; - impl.getValue(id, value, true); - return impl.loadDrawable(this, value, id, theme, true); - } finally { - releaseTempTypedValue(value); - } + return getDrawableForDensity(id, 0, theme); } /** @@ -844,7 +837,9 @@ public class Resources { * This integer encodes the package, type, and resource entry. * The value 0 is an invalid identifier. * @param density the desired screen density indicated by the resource as - * found in {@link DisplayMetrics}. + * found in {@link DisplayMetrics}. A value of 0 means to use the + * density returned from {@link #getConfiguration()}. + * This is equivalent to calling {@link #getDrawable(int)}. * @return Drawable An object that can be used to draw this resource. * @throws NotFoundException Throws NotFoundException if the given ID does * not exist. @@ -865,7 +860,9 @@ public class Resources { * This integer encodes the package, type, and resource entry. * The value 0 is an invalid identifier. * @param density The desired screen density indicated by the resource as - * found in {@link DisplayMetrics}. + * found in {@link DisplayMetrics}. A value of 0 means to use the + * density returned from {@link #getConfiguration()}. + * This is equivalent to calling {@link #getDrawable(int, Theme)}. * @param theme The theme used to style the drawable attributes, may be {@code null}. * @return Drawable An object that can be used to draw this resource. * @throws NotFoundException Throws NotFoundException if the given ID does @@ -876,37 +873,16 @@ public class Resources { try { final ResourcesImpl impl = mResourcesImpl; impl.getValueForDensity(id, density, value, true); - - // If the drawable's XML lives in our current density qualifier, - // it's okay to use a scaled version from the cache. Otherwise, we - // need to actually load the drawable from XML. - final DisplayMetrics metrics = impl.getDisplayMetrics(); - final boolean useCache = value.density == metrics.densityDpi; - - /* - * Pretend the requested density is actually the display density. If - * the drawable returned is not the requested density, then force it - * to be scaled later by dividing its density by the ratio of - * requested density to actual device density. Drawables that have - * undefined density or no density don't need to be handled here. - */ - if (value.density > 0 && value.density != TypedValue.DENSITY_NONE) { - if (value.density == density) { - value.density = metrics.densityDpi; - } else { - value.density = (value.density * metrics.densityDpi) / density; - } - } - return impl.loadDrawable(this, value, id, theme, useCache); + return impl.loadDrawable(this, value, id, density, theme); } finally { releaseTempTypedValue(value); } } @NonNull - Drawable loadDrawable(@NonNull TypedValue value, int id, @Nullable Theme theme) + Drawable loadDrawable(@NonNull TypedValue value, int id, int density, @Nullable Theme theme) throws NotFoundException { - return mResourcesImpl.loadDrawable(this, value, id, theme, true); + return mResourcesImpl.loadDrawable(this, value, id, density, theme); } /** @@ -1221,8 +1197,7 @@ public class Resources { * used to open drawable, sound, and raw resources; it will fail on string * and color resources. * - * @param id The resource identifier to open, as generated by the appt - * tool. + * @param id The resource identifier to open, as generated by the aapt tool. * * @return InputStream Access to the resource data. * @@ -1278,7 +1253,7 @@ public class Resources { * used to open drawable, sound, and raw resources; it will fail on string * and color resources. * - * @param id The resource identifier to open, as generated by the appt tool. + * @param id The resource identifier to open, as generated by the aapt tool. * @param value The TypedValue object to hold the resource information. * * @return InputStream Access to the resource data. @@ -1300,8 +1275,7 @@ public class Resources { * as uncompressed data, which typically includes things like mp3 files * and png images. * - * @param id The resource identifier to open, as generated by the appt - * tool. + * @param id The resource identifier to open, as generated by the aapt tool. * * @return AssetFileDescriptor A new file descriptor you can use to read * the resource. This includes the file descriptor itself, as well as the diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index f9acab97b40b..02ddc89f177e 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -523,8 +523,27 @@ public class ResourcesImpl { } @Nullable - Drawable loadDrawable(Resources wrapper, TypedValue value, int id, Resources.Theme theme, - boolean useCache) throws NotFoundException { + Drawable loadDrawable(@NonNull Resources wrapper, @NonNull TypedValue value, int id, + int density, @Nullable Resources.Theme theme) + throws NotFoundException { + // If the drawable's XML lives in our current density qualifier, + // it's okay to use a scaled version from the cache. Otherwise, we + // need to actually load the drawable from XML. + final boolean useCache = density == 0 || value.density == mMetrics.densityDpi; + + // Pretend the requested density is actually the display density. If + // the drawable returned is not the requested density, then force it + // to be scaled later by dividing its density by the ratio of + // requested density to actual device density. Drawables that have + // undefined density or no density don't need to be handled here. + if (density > 0 && value.density > 0 && value.density != TypedValue.DENSITY_NONE) { + if (value.density == density) { + value.density = mMetrics.densityDpi; + } else { + value.density = (value.density * mMetrics.densityDpi) / density; + } + } + try { if (TRACE_FOR_PRELOAD) { // Log only framework resources @@ -576,7 +595,7 @@ public class ResourcesImpl { } else if (isColorDrawable) { dr = new ColorDrawable(value.data); } else { - dr = loadDrawableForCookie(wrapper, value, id, null); + dr = loadDrawableForCookie(wrapper, value, id, density, null); } // Determine if the drawable has unresolved theme attributes. If it @@ -691,8 +710,8 @@ public class ResourcesImpl { /** * Loads a drawable from XML or resources stream. */ - private Drawable loadDrawableForCookie(Resources wrapper, TypedValue value, int id, - Resources.Theme theme) { + private Drawable loadDrawableForCookie(@NonNull Resources wrapper, @NonNull TypedValue value, + int id, int density, @Nullable Resources.Theme theme) { if (value.string == null) { throw new NotFoundException("Resource \"" + getResourceName(id) + "\" (" + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value); @@ -722,7 +741,7 @@ public class ResourcesImpl { if (file.endsWith(".xml")) { final XmlResourceParser rp = loadXmlResourceParser( file, id, value.assetCookie, "drawable"); - dr = Drawable.createFromXml(wrapper, rp, theme); + dr = Drawable.createFromXmlForDensity(wrapper, rp, density, theme); rp.close(); } else { final InputStream is = mAssets.openNonAsset( diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java index 88bb1a4ce3b9..0b0f048196a5 100644 --- a/core/java/android/content/res/TypedArray.java +++ b/core/java/android/content/res/TypedArray.java @@ -923,6 +923,15 @@ public class TypedArray { */ @Nullable public Drawable getDrawable(@StyleableRes int index) { + return getDrawableForDensity(index, 0); + } + + /** + * Version of {@link #getDrawable(int)} that accepts an override density. + * @hide + */ + @Nullable + public Drawable getDrawableForDensity(@StyleableRes int index, int density) { if (mRecycled) { throw new RuntimeException("Cannot make calls to a recycled instance!"); } @@ -933,7 +942,13 @@ public class TypedArray { throw new UnsupportedOperationException( "Failed to resolve attribute at index " + index + ": " + value); } - return mResources.loadDrawable(value, value.resourceId, mTheme); + + if (density > 0) { + // If the density is overridden, the value in the TypedArray will not reflect this. + // Do a separate lookup of the resourceId with the density override. + mResources.getValueForDensity(value.resourceId, density, value, true); + } + return mResources.loadDrawable(value, value.resourceId, density, mTheme); } return null; } diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java index 283a3e2b0b1e..ffadad9d68c5 100644 --- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java +++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java @@ -16,8 +16,6 @@ package android.graphics.drawable; -import static android.graphics.drawable.Drawable.obtainAttributes; - import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; @@ -218,14 +216,16 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback // The density may have changed since the last update. This will // apply scaling to any existing constant state properties. - final int density = Drawable.resolveDensity(r, 0); - state.setDensity(density); + final int deviceDensity = Drawable.resolveDensity(r, 0); + state.setDensity(deviceDensity); + state.mSrcDensityOverride = mSrcDensityOverride; final ChildDrawable[] array = state.mChildren; for (int i = 0; i < state.mChildren.length; i++) { final ChildDrawable layer = array[i]; - layer.setDensity(density); + layer.setDensity(deviceDensity); } + inflateLayers(r, parser, attrs, theme); } @@ -444,7 +444,7 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback /** * Inflates child layers using the specified parser. */ - void inflateLayers(@NonNull Resources r, @NonNull XmlPullParser parser, + private void inflateLayers(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { final LayerState state = mLayerState; @@ -491,7 +491,8 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback } // We found a child drawable. Take ownership. - layer.mDrawable = Drawable.createFromXmlInner(r, parser, attrs, theme); + layer.mDrawable = Drawable.createFromXmlInnerForDensity(r, parser, attrs, + mLayerState.mSrcDensityOverride, theme); layer.mDrawable.setCallback(this); state.mChildrenChangingConfigurations |= layer.mDrawable.getChangingConfigurations(); @@ -509,7 +510,8 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback // Extract the theme attributes, if any. layer.mThemeAttrs = a.extractThemeAttrs(); - Drawable dr = a.getDrawable(R.styleable.AdaptiveIconDrawableLayer_drawable); + Drawable dr = a.getDrawableForDensity(R.styleable.AdaptiveIconDrawableLayer_drawable, + state.mSrcDensityOverride); if (dr != null) { if (layer.mDrawable != null) { // It's possible that a drawable was already set, in which case @@ -951,7 +953,13 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback final static int N_CHILDREN = 2; ChildDrawable[] mChildren; + // The density at which to render the drawable and its children. int mDensity; + + // The density to use when inflating/looking up the children drawables. A value of 0 means + // use the system's density. + int mSrcDensityOverride = 0; + int mOpacityOverride = PixelFormat.UNKNOWN; @Config int mChangingConfigurations; @@ -986,6 +994,7 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback mAutoMirrored = orig.mAutoMirrored; mThemeAttrs = orig.mThemeAttrs; mOpacityOverride = orig.mOpacityOverride; + mSrcDensityOverride = orig.mSrcDensityOverride; } else { for (int i = 0; i < N_CHILDREN; i++) { mChildren[i] = new ChildDrawable(mDensity); diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index 5004667c1089..e3740e3cf284 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -41,6 +41,7 @@ import android.graphics.Xfermode; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.LayoutDirection; +import android.util.TypedValue; import android.view.Gravity; import com.android.internal.R; @@ -49,6 +50,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.io.InputStream; /** * A Drawable that wraps a bitmap and can be tiled, stretched, or aligned. You can create a @@ -749,7 +751,7 @@ public class BitmapDrawable extends Drawable { super.inflate(r, parser, attrs, theme); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.BitmapDrawable); - updateStateFromTypedArray(a); + updateStateFromTypedArray(a, mSrcDensityOverride); verifyRequiredAttributes(a); a.recycle(); @@ -775,7 +777,8 @@ public class BitmapDrawable extends Drawable { /** * Updates the constant state from the values in the typed array. */ - private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException { + private void updateStateFromTypedArray(TypedArray a, int srcDensityOverride) + throws XmlPullParserException { final Resources r = a.getResources(); final BitmapState state = mBitmapState; @@ -785,9 +788,37 @@ public class BitmapDrawable extends Drawable { // Extract the theme attributes, if any. state.mThemeAttrs = a.extractThemeAttrs(); + state.mSrcDensityOverride = srcDensityOverride; + + state.mTargetDensity = Drawable.resolveDensity(r, 0); + final int srcResId = a.getResourceId(R.styleable.BitmapDrawable_src, 0); if (srcResId != 0) { - final Bitmap bitmap = BitmapFactory.decodeResource(r, srcResId); + final TypedValue value = new TypedValue(); + r.getValueForDensity(srcResId, srcDensityOverride, value, true); + + // Pretend the requested density is actually the display density. If + // the drawable returned is not the requested density, then force it + // to be scaled later by dividing its density by the ratio of + // requested density to actual device density. Drawables that have + // undefined density or no density don't need to be handled here. + if (srcDensityOverride > 0 && value.density > 0 + && value.density != TypedValue.DENSITY_NONE) { + if (value.density == srcDensityOverride) { + value.density = r.getDisplayMetrics().densityDpi; + } else { + value.density = + (value.density * r.getDisplayMetrics().densityDpi) / srcDensityOverride; + } + } + + Bitmap bitmap = null; + try (InputStream is = r.openRawResource(srcResId, value)) { + bitmap = BitmapFactory.decodeResourceStream(r, value, is, null, null); + } catch (Exception e) { + // Do nothing and pick up the error below. + } + if (bitmap == null) { throw new XmlPullParserException(a.getPositionDescription() + ": <bitmap> requires a valid 'src' attribute"); @@ -796,8 +827,6 @@ public class BitmapDrawable extends Drawable { state.mBitmap = bitmap; } - state.mTargetDensity = r.getDisplayMetrics().densityDpi; - final boolean defMipMap = state.mBitmap != null ? state.mBitmap.hasMipMap() : false; setMipMap(a.getBoolean(R.styleable.BitmapDrawable_mipMap, defMipMap)); @@ -839,8 +868,6 @@ public class BitmapDrawable extends Drawable { if (tileModeY != TILE_MODE_UNDEFINED) { setTileModeY(parseTileMode(tileModeY)); } - - state.mTargetDensity = Drawable.resolveDensity(r, 0); } @Override @@ -855,7 +882,7 @@ public class BitmapDrawable extends Drawable { if (state.mThemeAttrs != null) { final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.BitmapDrawable); try { - updateStateFromTypedArray(a); + updateStateFromTypedArray(a, state.mSrcDensityOverride); } catch (XmlPullParserException e) { rethrowAsRuntimeException(e); } finally { @@ -929,7 +956,14 @@ public class BitmapDrawable extends Drawable { float mBaseAlpha = 1.0f; Shader.TileMode mTileModeX = null; Shader.TileMode mTileModeY = null; + + // The density to use when looking up the bitmap in Resources. A value of 0 means use + // the system's density. + int mSrcDensityOverride = 0; + + // The density at which to render the bitmap. int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT; + boolean mAutoMirrored = false; @Config int mChangingConfigurations; @@ -949,6 +983,7 @@ public class BitmapDrawable extends Drawable { mGravity = bitmapState.mGravity; mTileModeX = bitmapState.mTileModeX; mTileModeY = bitmapState.mTileModeY; + mSrcDensityOverride = bitmapState.mSrcDensityOverride; mTargetDensity = bitmapState.mTargetDensity; mBaseAlpha = bitmapState.mBaseAlpha; mPaint = new Paint(bitmapState.mPaint); diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 44fb1c75684e..f17cd768c386 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -189,6 +189,21 @@ public abstract class Drawable { private int mLayoutDirection; /** + * The source density to use when looking up resources using + * {@link Resources#getDrawableForDensity(int, int, Theme)}. A value of 0 means there is no + * override and the system density will be used. + * + * NOTE(adamlesinski): This is transient state used to get around the public API that does not + * account for source density overrides. Custom drawables implemented by developers do not need + * to be aware of the source density override, as it is only used by Launcher to load higher + * resolution icons from external Resources packages, which do not execute custom code. + * This is all to support the {@link Resources#getDrawableForDensity(int, int, Theme)} API. + * + * @hide + */ + protected int mSrcDensityOverride = 0; + + /** * Draw in its bounds (set via setBounds) respecting optional effects such * as alpha (set via setAlpha) and color filter (set via setColorFilter). * @@ -1197,7 +1212,8 @@ public abstract class Drawable { * create resources in XML, see * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>. */ - public static Drawable createFromXml(Resources r, XmlPullParser parser) + @NonNull + public static Drawable createFromXml(@NonNull Resources r, @NonNull XmlPullParser parser) throws XmlPullParserException, IOException { return createFromXml(r, parser, null); } @@ -1207,7 +1223,20 @@ public abstract class Drawable { * For more information on how to create resources in XML, see * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>. */ - public static Drawable createFromXml(Resources r, XmlPullParser parser, Theme theme) + @NonNull + public static Drawable createFromXml(@NonNull Resources r, @NonNull XmlPullParser parser, + @Nullable Theme theme) throws XmlPullParserException, IOException { + return createFromXmlForDensity(r, parser, 0, theme); + } + + /** + * Version of {@link #createFromXml(Resources, XmlPullParser, Theme)} that accepts a density + * override. + * @hide + */ + @NonNull + public static Drawable createFromXmlForDensity(@NonNull Resources r, + @NonNull XmlPullParser parser, int density, @Nullable Theme theme) throws XmlPullParserException, IOException { AttributeSet attrs = Xml.asAttributeSet(parser); @@ -1222,7 +1251,7 @@ public abstract class Drawable { throw new XmlPullParserException("No start tag found"); } - Drawable drawable = createFromXmlInner(r, parser, attrs, theme); + Drawable drawable = createFromXmlInnerForDensity(r, parser, attrs, density, theme); if (drawable == null) { throw new RuntimeException("Unknown initial tag: " + parser.getName()); @@ -1236,8 +1265,9 @@ public abstract class Drawable { * a tag in an XML document, tries to create a Drawable from that tag. * Returns null if the tag is not a valid drawable. */ - public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs) - throws XmlPullParserException, IOException { + @NonNull + public static Drawable createFromXmlInner(@NonNull Resources r, @NonNull XmlPullParser parser, + @NonNull AttributeSet attrs) throws XmlPullParserException, IOException { return createFromXmlInner(r, parser, attrs, null); } @@ -1247,14 +1277,29 @@ public abstract class Drawable { * document, tries to create a Drawable from that tag. Returns {@code null} * if the tag is not a valid drawable. */ - public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs, - Theme theme) throws XmlPullParserException, IOException { - return r.getDrawableInflater().inflateFromXml(parser.getName(), parser, attrs, theme); + @NonNull + public static Drawable createFromXmlInner(@NonNull Resources r, @NonNull XmlPullParser parser, + @NonNull AttributeSet attrs, @Nullable Theme theme) + throws XmlPullParserException, IOException { + return createFromXmlInnerForDensity(r, parser, attrs, 0, theme); + } + + /** + * Version of {@link #createFromXmlInner(Resources, XmlPullParser, AttributeSet, Theme)} that + * accepts an override density. + */ + @NonNull + static Drawable createFromXmlInnerForDensity(@NonNull Resources r, + @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, int density, + @Nullable Theme theme) throws XmlPullParserException, IOException { + return r.getDrawableInflater().inflateFromXmlForDensity(parser.getName(), parser, attrs, + density, theme); } /** * Create a drawable from file path name. */ + @Nullable public static Drawable createFromPath(String pathName) { if (pathName == null) { return null; @@ -1316,6 +1361,16 @@ public abstract class Drawable { } /** + * Sets the source override density for this Drawable. If non-zero, this density is to be used + * for any calls to {@link Resources#getDrawableForDensity(int, int, Theme)} or + * {@link Resources#getValueForDensity(int, int, TypedValue, boolean)}. + * @hide + */ + final void setSrcDensityOverride(int density) { + mSrcDensityOverride = density; + } + + /** * This abstract class is used by {@link Drawable}s to store shared constant state and data * between Drawables. {@link BitmapDrawable}s created from the same resource will for instance * share a unique bitmap stored in their ConstantState. diff --git a/graphics/java/android/graphics/drawable/DrawableInflater.java b/graphics/java/android/graphics/drawable/DrawableInflater.java index 3404d8c26910..eea7048ca534 100644 --- a/graphics/java/android/graphics/drawable/DrawableInflater.java +++ b/graphics/java/android/graphics/drawable/DrawableInflater.java @@ -112,6 +112,17 @@ public final class DrawableInflater { public Drawable inflateFromXml(@NonNull String name, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { + return inflateFromXmlForDensity(name, parser, attrs, 0, theme); + } + + /** + * Version of {@link #inflateFromXml(String, XmlPullParser, AttributeSet, Theme)} that accepts + * an override density. + */ + @NonNull + Drawable inflateFromXmlForDensity(@NonNull String name, @NonNull XmlPullParser parser, + @NonNull AttributeSet attrs, int density, @Nullable Theme theme) + throws XmlPullParserException, IOException { // Inner classes must be referenced as Outer$Inner, but XML tag names // can't contain $, so the <drawable> tag allows developers to specify // the class in an attribute. We'll still run it through inflateFromTag @@ -127,6 +138,7 @@ public final class DrawableInflater { if (drawable == null) { drawable = inflateFromClass(name); } + drawable.setSrcDensityOverride(density); drawable.inflate(mRes, parser, attrs, theme); return drawable; } diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java index 431b63bd64e5..cf821bb6ac8b 100644 --- a/graphics/java/android/graphics/drawable/DrawableWrapper.java +++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java @@ -131,6 +131,7 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb final int densityDpi = r.getDisplayMetrics().densityDpi; final int targetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; state.setDensity(targetDensity); + state.mSrcDensityOverride = mSrcDensityOverride; final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.DrawableWrapper); updateStateFromTypedArray(a); @@ -437,7 +438,8 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.START_TAG) { - dr = Drawable.createFromXmlInner(r, parser, attrs, theme); + dr = Drawable.createFromXmlInnerForDensity(r, parser, attrs, + mState.mSrcDensityOverride, theme); } } @@ -452,6 +454,14 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb @Config int mChangingConfigurations; int mDensity = DisplayMetrics.DENSITY_DEFAULT; + /** + * The density to use when looking up resources from + * {@link Resources#getDrawableForDensity(int, int, Theme)}. + * A value of 0 means there is no override and the system density will be used. + * @hide + */ + int mSrcDensityOverride = 0; + Drawable.ConstantState mDrawableState; DrawableWrapperState(@Nullable DrawableWrapperState orig, @Nullable Resources res) { @@ -459,6 +469,7 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb mThemeAttrs = orig.mThemeAttrs; mChangingConfigurations = orig.mChangingConfigurations; mDrawableState = orig.mDrawableState; + mSrcDensityOverride = orig.mSrcDensityOverride; } final int density; |