Merge "Support for changing density of DrawableWrapper subclasses"
This commit is contained in:
committed by
Android (Google) Code Review
commit
080d5eb5d7
@@ -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">
|
||||
@@ -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" />
|
||||
|
||||
@@ -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
|
||||
@@ -126,57 +126,21 @@ 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 {
|
||||
// If we're not waiting on a theme, verify required attributes.
|
||||
if (getDrawable() == null && (mState.mThemeAttrs == null
|
||||
|| mState.mThemeAttrs[R.styleable.AnimatedRotateDrawable_drawable] == 0)) {
|
||||
throw new XmlPullParserException(a.getPositionDescription()
|
||||
+ ": <animated-rotate> tag requires a 'drawable' attribute or "
|
||||
+ "child tag defining a drawable");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void updateStateFromTypedArray(TypedArray a) {
|
||||
super.updateStateFromTypedArray(a);
|
||||
public void applyTheme(@NonNull Theme t) {
|
||||
super.applyTheme(t);
|
||||
|
||||
final AnimatedRotateState state = mState;
|
||||
|
||||
if (a.hasValue(R.styleable.AnimatedRotateDrawable_pivotX)) {
|
||||
final TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX);
|
||||
state.mPivotXRel = tv.type == TypedValue.TYPE_FRACTION;
|
||||
state.mPivotX = state.mPivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
|
||||
}
|
||||
|
||||
if (a.hasValue(R.styleable.AnimatedRotateDrawable_pivotY)) {
|
||||
final TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotY);
|
||||
state.mPivotYRel = tv.type == TypedValue.TYPE_FRACTION;
|
||||
state.mPivotY = state.mPivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
|
||||
}
|
||||
|
||||
setFramesCount(a.getInt(
|
||||
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;
|
||||
@@ -195,13 +159,49 @@ public class AnimatedRotateDrawable extends DrawableWrapper implements Animatabl
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
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)) {
|
||||
throw new XmlPullParserException(a.getPositionDescription()
|
||||
+ ": <animated-rotate> tag requires a 'drawable' attribute or "
|
||||
+ "child tag defining a drawable");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
state.mPivotXRel = tv.type == TypedValue.TYPE_FRACTION;
|
||||
state.mPivotX = state.mPivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
|
||||
}
|
||||
|
||||
if (a.hasValue(R.styleable.AnimatedRotateDrawable_pivotY)) {
|
||||
final TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotY);
|
||||
state.mPivotYRel = tv.type == TypedValue.TYPE_FRACTION;
|
||||
state.mPivotY = state.mPivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
|
||||
}
|
||||
|
||||
setFramesCount(a.getInt(
|
||||
R.styleable.AnimatedRotateDrawable_framesCount, state.mFramesCount));
|
||||
setFramesDuration(a.getInt(
|
||||
R.styleable.AnimatedRotateDrawable_frameDuration, state.mFrameDuration));
|
||||
}
|
||||
|
||||
public void setFramesCount(int framesCount) {
|
||||
mState.mFramesCount = framesCount;
|
||||
mIncrement = 360.0f / mState.mFramesCount;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -59,7 +61,7 @@ public class ClipDrawable extends DrawableWrapper {
|
||||
private ClipState mState;
|
||||
|
||||
ClipDrawable() {
|
||||
this(new ClipState(null), null);
|
||||
this(new ClipState(null, null), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
public void applyTheme(@NonNull Theme t) {
|
||||
super.applyTheme(t);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTheme(Theme t) {
|
||||
final ClipState state = mState;
|
||||
if (state == null) {
|
||||
return;
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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() {
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.graphics.drawable;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -112,7 +116,66 @@ 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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.DrawableWrapper);
|
||||
updateStateFromTypedArray(a);
|
||||
a.recycle();
|
||||
|
||||
inflateChildDrawable(r, parser, attrs, theme);
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -124,20 +187,8 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb
|
||||
// Extract the theme attributes, if any.
|
||||
state.mThemeAttrs = a.extractThemeAttrs();
|
||||
|
||||
// TODO: Consider using R.styleable.DrawableWrapper_drawable
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTheme(Resources.Theme t) {
|
||||
super.applyTheme(t);
|
||||
|
||||
final DrawableWrapperState state = mState;
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDrawable != null && mDrawable.canApplyTheme()) {
|
||||
mDrawable.applyTheme(t);
|
||||
if (a.hasValueOrEmpty(R.styleable.DrawableWrapper_drawable)) {
|
||||
setDrawable(a.getDrawable(R.styleable.DrawableWrapper_drawable));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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() {
|
||||
|
||||
@@ -22,14 +22,17 @@ 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.Resources.Theme;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -58,7 +61,7 @@ public class InsetDrawable extends DrawableWrapper {
|
||||
* No-arg constructor used by drawable inflation.
|
||||
*/
|
||||
InsetDrawable() {
|
||||
this(new InsetState(null), null);
|
||||
this(new InsetState(null, null), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,7 +70,7 @@ public class InsetDrawable extends DrawableWrapper {
|
||||
* @param drawable The drawable to inset.
|
||||
* @param inset Inset in pixels around the drawable.
|
||||
*/
|
||||
public InsetDrawable(Drawable drawable, int inset) {
|
||||
public InsetDrawable(@Nullable Drawable drawable, int inset) {
|
||||
this(drawable, inset, inset, inset, inset);
|
||||
}
|
||||
|
||||
@@ -80,9 +83,9 @@ public class InsetDrawable extends DrawableWrapper {
|
||||
* @param insetRight Right inset in pixels.
|
||||
* @param insetBottom Bottom inset in pixels.
|
||||
*/
|
||||
public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,int insetRight,
|
||||
int insetBottom) {
|
||||
this(new InsetState(null), null);
|
||||
public InsetDrawable(@Nullable Drawable drawable, int insetLeft, int insetTop,
|
||||
int insetRight, int insetBottom) {
|
||||
this(new InsetState(null, null), null);
|
||||
|
||||
mState.mInsetLeft = insetLeft;
|
||||
mState.mInsetTop = insetTop;
|
||||
@@ -93,69 +96,23 @@ public class InsetDrawable 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.InsetDrawable);
|
||||
|
||||
// Inflation will advance the XmlPullParser and AttributeSet.
|
||||
super.inflate(r, parser, attrs, theme);
|
||||
|
||||
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.InsetDrawable);
|
||||
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.InsetDrawable_drawable] == 0)) {
|
||||
throw new XmlPullParserException(a.getPositionDescription()
|
||||
+ ": <inset> tag requires a 'drawable' attribute or "
|
||||
+ "child tag defining a drawable");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void updateStateFromTypedArray(TypedArray a) {
|
||||
super.updateStateFromTypedArray(a);
|
||||
public void applyTheme(@NonNull Theme t) {
|
||||
super.applyTheme(t);
|
||||
|
||||
final InsetState state = mState;
|
||||
final int N = a.getIndexCount();
|
||||
for (int i = 0; i < N; i++) {
|
||||
final int attr = a.getIndex(i);
|
||||
switch (attr) {
|
||||
case R.styleable.InsetDrawable_drawable:
|
||||
final Drawable dr = a.getDrawable(attr);
|
||||
if (dr != null) {
|
||||
setDrawable(dr);
|
||||
}
|
||||
break;
|
||||
case R.styleable.InsetDrawable_inset:
|
||||
final int inset = a.getDimensionPixelOffset(attr, Integer.MIN_VALUE);
|
||||
if (inset != Integer.MIN_VALUE) {
|
||||
state.mInsetLeft = inset;
|
||||
state.mInsetTop = inset;
|
||||
state.mInsetRight = inset;
|
||||
state.mInsetBottom = inset;
|
||||
}
|
||||
break;
|
||||
case R.styleable.InsetDrawable_insetLeft:
|
||||
state.mInsetLeft = a.getDimensionPixelOffset(attr, state.mInsetLeft);
|
||||
break;
|
||||
case R.styleable.InsetDrawable_insetTop:
|
||||
state.mInsetTop = a.getDimensionPixelOffset(attr, state.mInsetTop);
|
||||
break;
|
||||
case R.styleable.InsetDrawable_insetRight:
|
||||
state.mInsetRight = a.getDimensionPixelOffset(attr, state.mInsetRight);
|
||||
break;
|
||||
case R.styleable.InsetDrawable_insetBottom:
|
||||
state.mInsetBottom = a.getDimensionPixelOffset(attr, state.mInsetBottom);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTheme(Theme t) {
|
||||
final InsetState state = mState;
|
||||
if (state == null) {
|
||||
return;
|
||||
@@ -172,10 +129,47 @@ public class InsetDrawable 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.InsetDrawable_drawable] == 0)) {
|
||||
throw new XmlPullParserException(a.getPositionDescription()
|
||||
+ ": <inset> tag requires a 'drawable' attribute or "
|
||||
+ "child tag defining a drawable");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStateFromTypedArray(@NonNull TypedArray a) {
|
||||
final InsetState 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();
|
||||
|
||||
// Inset attribute may be overridden by more specific attributes.
|
||||
if (a.hasValue(R.styleable.InsetDrawable_inset)) {
|
||||
final int inset = a.getDimensionPixelOffset(R.styleable.InsetDrawable_inset, 0);
|
||||
state.mInsetLeft = inset;
|
||||
state.mInsetTop = inset;
|
||||
state.mInsetRight = inset;
|
||||
state.mInsetBottom = inset;
|
||||
}
|
||||
|
||||
state.mInsetLeft = a.getDimensionPixelOffset(
|
||||
R.styleable.InsetDrawable_insetLeft, state.mInsetLeft);
|
||||
state.mInsetRight = a.getDimensionPixelOffset(
|
||||
R.styleable.InsetDrawable_insetRight, state.mInsetRight);
|
||||
state.mInsetTop = a.getDimensionPixelOffset(
|
||||
R.styleable.InsetDrawable_insetTop, state.mInsetTop);
|
||||
state.mInsetBottom = a.getDimensionPixelOffset(
|
||||
R.styleable.InsetDrawable_insetBottom, state.mInsetBottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -243,30 +237,72 @@ public class InsetDrawable extends DrawableWrapper {
|
||||
|
||||
@Override
|
||||
DrawableWrapperState mutateConstantState() {
|
||||
mState = new InsetState(mState);
|
||||
mState = new InsetState(mState, null);
|
||||
return mState;
|
||||
}
|
||||
|
||||
static final class InsetState extends DrawableWrapper.DrawableWrapperState {
|
||||
private int[] mThemeAttrs;
|
||||
|
||||
int mInsetLeft = 0;
|
||||
int mInsetTop = 0;
|
||||
int mInsetRight = 0;
|
||||
int mInsetBottom = 0;
|
||||
|
||||
InsetState(InsetState orig) {
|
||||
super(orig);
|
||||
InsetState(@Nullable InsetState orig, @Nullable Resources res) {
|
||||
super(orig, res);
|
||||
|
||||
if (orig != null) {
|
||||
mInsetLeft = orig.mInsetLeft;
|
||||
mInsetTop = orig.mInsetTop;
|
||||
mInsetRight = orig.mInsetRight;
|
||||
mInsetBottom = orig.mInsetBottom;
|
||||
|
||||
if (orig.mDensity != mDensity) {
|
||||
applyDensityScaling(orig.mDensity, mDensity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable newDrawable(Resources res) {
|
||||
return new InsetDrawable(this, res);
|
||||
void onDensityChanged(int sourceDensity, int targetDensity) {
|
||||
super.onDensityChanged(sourceDensity, targetDensity);
|
||||
|
||||
applyDensityScaling(sourceDensity, targetDensity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the constant state density changes to scale
|
||||
* density-dependent properties specific to insets.
|
||||
*
|
||||
* @param sourceDensity the previous constant state density
|
||||
* @param targetDensity the new constant state density
|
||||
*/
|
||||
private void applyDensityScaling(int sourceDensity, int targetDensity) {
|
||||
mInsetLeft = Bitmap.scaleFromDensity(mInsetLeft, sourceDensity, targetDensity);
|
||||
mInsetTop = Bitmap.scaleFromDensity(mInsetTop, sourceDensity, targetDensity);
|
||||
mInsetRight = Bitmap.scaleFromDensity(mInsetRight, sourceDensity, targetDensity);
|
||||
mInsetBottom = Bitmap.scaleFromDensity(mInsetBottom, sourceDensity, targetDensity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable newDrawable(@Nullable Resources res) {
|
||||
// If this drawable is being created for a different density,
|
||||
// just create a new constant state and call it a day.
|
||||
final InsetState state;
|
||||
if (res != null) {
|
||||
final int densityDpi = res.getDisplayMetrics().densityDpi;
|
||||
final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
|
||||
if (density != mDensity) {
|
||||
state = new InsetState(this, res);
|
||||
} else {
|
||||
state = this;
|
||||
}
|
||||
} else {
|
||||
state = this;
|
||||
}
|
||||
|
||||
return new InsetDrawable(state, res);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,7 +310,7 @@ public class InsetDrawable extends DrawableWrapper {
|
||||
* The one constructor to rule them all. This is called by all public
|
||||
* constructors to set the state and initialize local properties.
|
||||
*/
|
||||
private InsetDrawable(InsetState state, Resources res) {
|
||||
private InsetDrawable(@NonNull InsetState state, @Nullable Resources res) {
|
||||
super(state, res);
|
||||
|
||||
mState = state;
|
||||
|
||||
@@ -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.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.content.res.Resources;
|
||||
@@ -58,22 +60,46 @@ public class RotateDrawable extends DrawableWrapper {
|
||||
* Creates a new rotating drawable with no wrapped drawable.
|
||||
*/
|
||||
public RotateDrawable() {
|
||||
this(new RotateState(null), null);
|
||||
this(new RotateState(null, null), null);
|
||||
}
|
||||
|
||||
@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.RotateDrawable);
|
||||
super.inflateWithAttributes(r, parser, a, R.styleable.RotateDrawable_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();
|
||||
}
|
||||
|
||||
private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
|
||||
@Override
|
||||
public void applyTheme(@NonNull Theme t) {
|
||||
super.applyTheme(t);
|
||||
|
||||
final RotateState state = mState;
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.mThemeAttrs != null) {
|
||||
final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.RotateDrawable);
|
||||
try {
|
||||
updateStateFromTypedArray(a);
|
||||
verifyRequiredAttributes(a);
|
||||
} catch (XmlPullParserException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.RotateDrawable_drawable] == 0)) {
|
||||
@@ -83,11 +109,14 @@ public class RotateDrawable extends DrawableWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void updateStateFromTypedArray(TypedArray a) {
|
||||
super.updateStateFromTypedArray(a);
|
||||
|
||||
private void updateStateFromTypedArray(@NonNull TypedArray a) {
|
||||
final RotateState 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();
|
||||
@@ -109,35 +138,6 @@ public class RotateDrawable extends DrawableWrapper {
|
||||
state.mToDegrees = a.getFloat(
|
||||
R.styleable.RotateDrawable_toDegrees, state.mToDegrees);
|
||||
state.mCurrentDegrees = state.mFromDegrees;
|
||||
|
||||
final Drawable dr = a.getDrawable(R.styleable.RotateDrawable_drawable);
|
||||
if (dr != null) {
|
||||
setDrawable(dr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTheme(Theme t) {
|
||||
final RotateState state = mState;
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.mThemeAttrs != null) {
|
||||
final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.RotateDrawable);
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -316,11 +316,13 @@ public class RotateDrawable extends DrawableWrapper {
|
||||
|
||||
@Override
|
||||
DrawableWrapperState mutateConstantState() {
|
||||
mState = new RotateState(mState);
|
||||
mState = new RotateState(mState, null);
|
||||
return mState;
|
||||
}
|
||||
|
||||
static final class RotateState extends DrawableWrapper.DrawableWrapperState {
|
||||
private int[] mThemeAttrs;
|
||||
|
||||
boolean mPivotXRel = true;
|
||||
float mPivotX = 0.5f;
|
||||
boolean mPivotYRel = true;
|
||||
@@ -329,8 +331,8 @@ public class RotateDrawable extends DrawableWrapper {
|
||||
float mToDegrees = 360.0f;
|
||||
float mCurrentDegrees = 0.0f;
|
||||
|
||||
RotateState(RotateState orig) {
|
||||
super(orig);
|
||||
RotateState(RotateState orig, Resources res) {
|
||||
super(orig, res);
|
||||
|
||||
if (orig != null) {
|
||||
mPivotXRel = orig.mPivotXRel;
|
||||
|
||||
@@ -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.Resources.Theme;
|
||||
import android.content.res.TypedArray;
|
||||
@@ -67,7 +69,7 @@ public class ScaleDrawable extends DrawableWrapper {
|
||||
private ScaleState mState;
|
||||
|
||||
ScaleDrawable() {
|
||||
this(new ScaleState(null), null);
|
||||
this(new ScaleState(null, null), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,7 +85,7 @@ public class ScaleDrawable extends DrawableWrapper {
|
||||
* is at the maximum value, or -1 to not scale height
|
||||
*/
|
||||
public ScaleDrawable(Drawable drawable, int gravity, float scaleWidth, float scaleHeight) {
|
||||
this(new ScaleState(null), null);
|
||||
this(new ScaleState(null, null), null);
|
||||
|
||||
mState.mGravity = gravity;
|
||||
mState.mScaleWidth = scaleWidth;
|
||||
@@ -93,20 +95,46 @@ public class ScaleDrawable 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.ScaleDrawable);
|
||||
|
||||
// Inflation will advance the XmlPullParser and AttributeSet.
|
||||
super.inflate(r, parser, attrs, theme);
|
||||
|
||||
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ScaleDrawable);
|
||||
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 ScaleState state = mState;
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.mThemeAttrs != null) {
|
||||
final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ScaleDrawable);
|
||||
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.ScaleDrawable_drawable] == 0)) {
|
||||
@@ -116,11 +144,18 @@ public class ScaleDrawable extends DrawableWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void updateStateFromTypedArray(TypedArray a) {
|
||||
super.updateStateFromTypedArray(a);
|
||||
|
||||
private void updateStateFromTypedArray(@NonNull TypedArray a) {
|
||||
final ScaleState 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.mScaleWidth = getPercent(a,
|
||||
R.styleable.ScaleDrawable_scaleWidth, state.mScaleWidth);
|
||||
state.mScaleHeight = getPercent(a,
|
||||
@@ -131,11 +166,6 @@ public class ScaleDrawable extends DrawableWrapper {
|
||||
R.styleable.ScaleDrawable_useIntrinsicSizeAsMinimum, state.mUseIntrinsicSizeAsMin);
|
||||
state.mInitialLevel = a.getInt(
|
||||
R.styleable.ScaleDrawable_level, state.mInitialLevel);
|
||||
|
||||
final Drawable dr = a.getDrawable(R.styleable.ScaleDrawable_drawable);
|
||||
if (dr != null) {
|
||||
setDrawable(dr);
|
||||
}
|
||||
}
|
||||
|
||||
private static float getPercent(TypedArray a, int index, float defaultValue) {
|
||||
@@ -156,33 +186,6 @@ public class ScaleDrawable extends DrawableWrapper {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTheme(Theme t) {
|
||||
final ScaleState state = mState;
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.mThemeAttrs != null) {
|
||||
final TypedArray a = t.resolveAttributes(
|
||||
state.mThemeAttrs, R.styleable.ScaleDrawable);
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
final Drawable d = getDrawable();
|
||||
@@ -243,7 +246,7 @@ public class ScaleDrawable extends DrawableWrapper {
|
||||
|
||||
@Override
|
||||
DrawableWrapperState mutateConstantState() {
|
||||
mState = new ScaleState(mState);
|
||||
mState = new ScaleState(mState, null);
|
||||
return mState;
|
||||
}
|
||||
|
||||
@@ -251,14 +254,16 @@ public class ScaleDrawable extends DrawableWrapper {
|
||||
/** Constant used to disable scaling for a particular dimension. */
|
||||
private static final float DO_NOT_SCALE = -1.0f;
|
||||
|
||||
private int[] mThemeAttrs;
|
||||
|
||||
float mScaleWidth = DO_NOT_SCALE;
|
||||
float mScaleHeight = DO_NOT_SCALE;
|
||||
int mGravity = Gravity.LEFT;
|
||||
boolean mUseIntrinsicSizeAsMin = false;
|
||||
int mInitialLevel = 0;
|
||||
|
||||
ScaleState(ScaleState orig) {
|
||||
super(orig);
|
||||
ScaleState(ScaleState orig, Resources res) {
|
||||
super(orig, res);
|
||||
|
||||
if (orig != null) {
|
||||
mScaleWidth = orig.mScaleWidth;
|
||||
|
||||
Reference in New Issue
Block a user