am 425b1dc8: Merge "Add theme and config change support to more Drawable types" into lmp-mr1-dev

* commit '425b1dc88c47e0e9d3a653ad902a69f3ec09b966':
  Add theme and config change support to more Drawable types
This commit is contained in:
Alan Viverette
2014-10-30 00:30:11 +00:00
committed by Android Git Automerger
14 changed files with 696 additions and 444 deletions

View File

@@ -16,6 +16,8 @@
package android.graphics.drawable; package android.graphics.drawable;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.ColorFilter; import android.graphics.ColorFilter;
@@ -41,6 +43,7 @@ import com.android.internal.R;
*/ */
public class AnimatedRotateDrawable extends Drawable implements Drawable.Callback, Runnable, public class AnimatedRotateDrawable extends Drawable implements Drawable.Callback, Runnable,
Animatable { Animatable {
private static final String TAG = "AnimatedRotateDrawable";
private AnimatedRotateState mState; private AnimatedRotateState mState;
private boolean mMutated; private boolean mMutated;
@@ -185,6 +188,11 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
return mState.mDrawable.getOpacity(); return mState.mDrawable.getOpacity();
} }
@Override
public boolean canApplyTheme() {
return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
}
@Override @Override
public void invalidateDrawable(Drawable who) { public void invalidateDrawable(Drawable who) {
final Callback callback = getCallback(); final Callback callback = getCallback();
@@ -254,67 +262,21 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
} }
@Override @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 { throws XmlPullParserException, IOException {
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimatedRotateDrawable); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimatedRotateDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible); super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible);
updateStateFromTypedArray(a);
TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX);
final boolean pivotXRel = tv.type == TypedValue.TYPE_FRACTION;
final float pivotX = pivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotY);
final boolean pivotYRel = tv.type == TypedValue.TYPE_FRACTION;
final float pivotY = pivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
setFramesCount(a.getInt(R.styleable.AnimatedRotateDrawable_framesCount, 12));
setFramesDuration(a.getInt(R.styleable.AnimatedRotateDrawable_frameDuration, 150));
final int res = a.getResourceId(R.styleable.AnimatedRotateDrawable_drawable, 0);
Drawable drawable = null;
if (res > 0) {
drawable = r.getDrawable(res, theme);
}
a.recycle(); a.recycle();
int outerDepth = parser.getDepth(); inflateChildElements(r, parser, attrs, theme);
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT &&
(type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
if ((drawable = Drawable.createFromXmlInner(r, parser, attrs, theme)) == null) {
Log.w("drawable", "Bad element under <animated-rotate>: "
+ parser .getName());
}
}
if (drawable == null) {
Log.w("drawable", "No drawable specified for <animated-rotate>");
}
final AnimatedRotateState rotateState = mState;
rotateState.mDrawable = drawable;
rotateState.mPivotXRel = pivotXRel;
rotateState.mPivotX = pivotX;
rotateState.mPivotYRel = pivotYRel;
rotateState.mPivotY = pivotY;
init(); init();
if (drawable != null) {
drawable.setCallback(this);
}
} }
@Override @Override
public void applyTheme(Theme t) { public void applyTheme(@Nullable Theme t) {
super.applyTheme(t); super.applyTheme(t);
final AnimatedRotateState state = mState; final AnimatedRotateState state = mState;
@@ -322,15 +284,91 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
return; return;
} }
if (state.mDrawable != null) { 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();
}
}
if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
state.mDrawable.applyTheme(t); state.mDrawable.applyTheme(t);
} }
init();
}
private void updateStateFromTypedArray(TypedArray a) {
final AnimatedRotateState state = mState;
// 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));
final Drawable dr = a.getDrawable(R.styleable.AnimatedRotateDrawable_drawable);
if (dr != null) {
state.mDrawable = dr;
dr.setCallback(this);
}
} }
@Override private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
public boolean canApplyTheme() { Theme theme) throws XmlPullParserException, IOException {
final AnimatedRotateState state = mState; final AnimatedRotateState state = mState;
return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme();
Drawable dr = null;
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
if ((dr = Drawable.createFromXmlInner(r, parser, attrs, theme)) == null) {
Log.w(TAG, "Bad element under <animated-rotate>: " + parser.getName());
}
}
if (dr != null) {
state.mDrawable = dr;
dr.setCallback(this);
}
}
private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
// If we're not waiting on a theme, verify required attributes.
if (mState.mDrawable == 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");
}
} }
public void setFramesCount(int framesCount) { public void setFramesCount(int framesCount) {
@@ -362,15 +400,16 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
final static class AnimatedRotateState extends Drawable.ConstantState { final static class AnimatedRotateState extends Drawable.ConstantState {
Drawable mDrawable; Drawable mDrawable;
int[] mThemeAttrs;
int mChangingConfigurations; int mChangingConfigurations;
boolean mPivotXRel; boolean mPivotXRel = false;
float mPivotX; float mPivotX = 0;
boolean mPivotYRel; boolean mPivotYRel = false;
float mPivotY; float mPivotY = 0;
int mFrameDuration; int mFrameDuration = 150;
int mFramesCount; int mFramesCount = 12;
private boolean mCanConstantState; private boolean mCanConstantState;
private boolean mCheckedConstantState; private boolean mCheckedConstantState;
@@ -387,6 +426,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection()); mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
mDrawable.setBounds(orig.mDrawable.getBounds()); mDrawable.setBounds(orig.mDrawable.getBounds());
mDrawable.setLevel(orig.mDrawable.getLevel()); mDrawable.setLevel(orig.mDrawable.getLevel());
mThemeAttrs = orig.mThemeAttrs;
mPivotXRel = orig.mPivotXRel; mPivotXRel = orig.mPivotXRel;
mPivotX = orig.mPivotX; mPivotX = orig.mPivotX;
mPivotYRel = orig.mPivotYRel; mPivotYRel = orig.mPivotYRel;
@@ -407,6 +447,12 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
return new AnimatedRotateDrawable(this, res); return new AnimatedRotateDrawable(this, res);
} }
@Override
public boolean canApplyTheme() {
return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
|| super.canApplyTheme();
}
@Override @Override
public int getChangingConfigurations() { public int getChangingConfigurations() {
return mChangingConfigurations; return mChangingConfigurations;

View File

@@ -347,24 +347,62 @@ public class AnimatedStateListDrawable extends StateListDrawable {
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
final TypedArray a = obtainAttributes( final TypedArray a = obtainAttributes(
r, theme, attrs, R.styleable.AnimatedStateListDrawable); r, theme, attrs, R.styleable.AnimatedStateListDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedStateListDrawable_visible); super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedStateListDrawable_visible);
updateStateFromTypedArray(a);
final StateListState stateListState = getStateListState();
stateListState.setVariablePadding(a.getBoolean(
R.styleable.AnimatedStateListDrawable_variablePadding, false));
stateListState.setConstantSize(a.getBoolean(
R.styleable.AnimatedStateListDrawable_constantSize, false));
stateListState.setEnterFadeDuration(a.getInt(
R.styleable.AnimatedStateListDrawable_enterFadeDuration, 0));
stateListState.setExitFadeDuration(a.getInt(
R.styleable.AnimatedStateListDrawable_exitFadeDuration, 0));
setDither(a.getBoolean(R.styleable.AnimatedStateListDrawable_dither, true));
setAutoMirrored(a.getBoolean(R.styleable.AnimatedStateListDrawable_autoMirrored, false));
a.recycle(); a.recycle();
inflateChildElements(r, parser, attrs, theme);
init();
}
@Override
public void applyTheme(@Nullable Theme theme) {
super.applyTheme(theme);
final AnimatedStateListState state = mState;
if (state == null || !state.canApplyTheme()) {
return;
}
final TypedArray a = theme.resolveAttributes(
state.mAnimThemeAttrs, R.styleable.AnimatedRotateDrawable);
updateStateFromTypedArray(a);
a.recycle();
init();
}
private void updateStateFromTypedArray(TypedArray a) {
final AnimatedStateListState state = mState;
// Account for any configuration changes.
state.mChangingConfigurations |= a.getChangingConfigurations();
// Extract the theme attributes, if any.
state.mAnimThemeAttrs = a.extractThemeAttrs();
state.setVariablePadding(a.getBoolean(
R.styleable.AnimatedStateListDrawable_variablePadding, state.mVariablePadding));
state.setConstantSize(a.getBoolean(
R.styleable.AnimatedStateListDrawable_constantSize, state.mConstantSize));
state.setEnterFadeDuration(a.getInt(
R.styleable.AnimatedStateListDrawable_enterFadeDuration, state.mEnterFadeDuration));
state.setExitFadeDuration(a.getInt(
R.styleable.AnimatedStateListDrawable_exitFadeDuration, state.mExitFadeDuration));
setDither(a.getBoolean(
R.styleable.AnimatedStateListDrawable_dither, state.mDither));
setAutoMirrored(a.getBoolean(
R.styleable.AnimatedStateListDrawable_autoMirrored, state.mAutoMirrored));
}
private void init() {
onStateChange(getState());
}
private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
Theme theme) throws XmlPullParserException, IOException {
int type; int type;
final int innerDepth = parser.getDepth() + 1; final int innerDepth = parser.getDepth() + 1;
@@ -386,8 +424,6 @@ public class AnimatedStateListDrawable extends StateListDrawable {
parseTransition(r, parser, attrs, theme); parseTransition(r, parser, attrs, theme);
} }
} }
onStateChange(getState());
} }
private int parseTransition(@NonNull Resources r, @NonNull XmlPullParser parser, private int parseTransition(@NonNull Resources r, @NonNull XmlPullParser parser,
@@ -507,6 +543,8 @@ public class AnimatedStateListDrawable extends StateListDrawable {
private static final int REVERSE_SHIFT = 32; private static final int REVERSE_SHIFT = 32;
private static final int REVERSE_MASK = 0x1; private static final int REVERSE_MASK = 0x1;
int[] mAnimThemeAttrs;
final LongSparseLongArray mTransitions; final LongSparseLongArray mTransitions;
final SparseIntArray mStateIds; final SparseIntArray mStateIds;
@@ -515,6 +553,7 @@ public class AnimatedStateListDrawable extends StateListDrawable {
super(orig, owner, res); super(orig, owner, res);
if (orig != null) { if (orig != null) {
mAnimThemeAttrs = orig.mAnimThemeAttrs;
mTransitions = orig.mTransitions.clone(); mTransitions = orig.mTransitions.clone();
mStateIds = orig.mStateIds.clone(); mStateIds = orig.mStateIds.clone();
} else { } else {
@@ -565,6 +604,11 @@ public class AnimatedStateListDrawable extends StateListDrawable {
return (mTransitions.get(keyFromTo, -1) >> REVERSE_SHIFT & REVERSE_MASK) == 1; return (mTransitions.get(keyFromTo, -1) >> REVERSE_SHIFT & REVERSE_MASK) == 1;
} }
@Override
public boolean canApplyTheme() {
return mAnimThemeAttrs != null || super.canApplyTheme();
}
@Override @Override
public Drawable newDrawable() { public Drawable newDrawable() {
return new AnimatedStateListDrawable(this, null); return new AnimatedStateListDrawable(this, null);

View File

@@ -316,9 +316,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
@Override @Override
public boolean canApplyTheme() { public boolean canApplyTheme() {
return super.canApplyTheme() || mAnimatedVectorState != null return (mAnimatedVectorState != null && mAnimatedVectorState.canApplyTheme())
&& mAnimatedVectorState.mVectorDrawable != null || super.canApplyTheme();
&& mAnimatedVectorState.mVectorDrawable.canApplyTheme();
} }
@Override @Override
@@ -373,6 +372,12 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
} }
} }
@Override
public boolean canApplyTheme() {
return (mVectorDrawable != null && mVectorDrawable.canApplyTheme())
|| super.canApplyTheme();
}
@Override @Override
public Drawable newDrawable() { public Drawable newDrawable() {
return new AnimatedVectorDrawable(this, null); return new AnimatedVectorDrawable(this, null);

View File

@@ -16,6 +16,8 @@
package android.graphics.drawable; package android.graphics.drawable;
import com.android.internal.R;
import java.io.IOException; import java.io.IOException;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
@@ -271,27 +273,25 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
@Override @Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimationDrawable);
TypedArray a = obtainAttributes(r, theme, attrs, super.inflateWithAttributes(r, parser, a, R.styleable.AnimationDrawable_visible);
com.android.internal.R.styleable.AnimationDrawable); updateStateFromTypedArray(a);
super.inflateWithAttributes(r, parser, a,
com.android.internal.R.styleable.AnimationDrawable_visible);
mAnimationState.setVariablePadding(a.getBoolean(
com.android.internal.R.styleable.AnimationDrawable_variablePadding, false));
mAnimationState.mOneShot = a.getBoolean(
com.android.internal.R.styleable.AnimationDrawable_oneshot, false);
a.recycle(); a.recycle();
inflateChildElements(r, parser, attrs, theme);
setFrame(0, true, false);
}
private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
Theme theme) throws XmlPullParserException, IOException {
TypedArray a;
int type; int type;
final int innerDepth = parser.getDepth()+1; final int innerDepth = parser.getDepth()+1;
int depth; int depth;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT && while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) { && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
if (type != XmlPullParser.START_TAG) { if (type != XmlPullParser.START_TAG) {
continue; continue;
} }
@@ -300,17 +300,15 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
continue; continue;
} }
a = obtainAttributes( a = obtainAttributes(r, theme, attrs, R.styleable.AnimationDrawableItem);
r, theme, attrs, com.android.internal.R.styleable.AnimationDrawableItem);
int duration = a.getInt( final int duration = a.getInt(R.styleable.AnimationDrawableItem_duration, -1);
com.android.internal.R.styleable.AnimationDrawableItem_duration, -1);
if (duration < 0) { if (duration < 0) {
throw new XmlPullParserException( throw new XmlPullParserException(parser.getPositionDescription()
parser.getPositionDescription()
+ ": <item> tag requires a 'duration' attribute"); + ": <item> tag requires a 'duration' attribute");
} }
int drawableRes = a.getResourceId(
com.android.internal.R.styleable.AnimationDrawableItem_drawable, 0); final int drawableRes = a.getResourceId(R.styleable.AnimationDrawableItem_drawable, 0);
a.recycle(); a.recycle();
@@ -322,9 +320,9 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
// Empty // Empty
} }
if (type != XmlPullParser.START_TAG) { if (type != XmlPullParser.START_TAG) {
throw new XmlPullParserException(parser.getPositionDescription() + throw new XmlPullParserException(parser.getPositionDescription()
": <item> tag requires a 'drawable' attribute or child tag" + + ": <item> tag requires a 'drawable' attribute or child tag"
" defining a drawable"); + " defining a drawable");
} }
dr = Drawable.createFromXmlInner(r, parser, attrs, theme); dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
} }
@@ -334,8 +332,14 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
dr.setCallback(this); dr.setCallback(this);
} }
} }
}
setFrame(0, true, false); private void updateStateFromTypedArray(TypedArray a) {
mAnimationState.mVariablePadding = a.getBoolean(
R.styleable.AnimationDrawable_variablePadding, mAnimationState.mVariablePadding);
mAnimationState.mOneShot = a.getBoolean(
R.styleable.AnimationDrawable_oneshot, mAnimationState.mOneShot);
} }
@Override @Override
@@ -357,7 +361,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
private final static class AnimationState extends DrawableContainerState { private final static class AnimationState extends DrawableContainerState {
private int[] mDurations; private int[] mDurations;
private boolean mOneShot; private boolean mOneShot = false;
AnimationState(AnimationState orig, AnimationDrawable owner, AnimationState(AnimationState orig, AnimationDrawable owner,
Resources res) { Resources res) {

View File

@@ -16,6 +16,8 @@
package android.graphics.drawable; package android.graphics.drawable;
import com.android.internal.R;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
@@ -49,7 +51,7 @@ import java.io.IOException;
* @attr ref android.R.styleable#ClipDrawable_drawable * @attr ref android.R.styleable#ClipDrawable_drawable
*/ */
public class ClipDrawable extends Drawable implements Drawable.Callback { public class ClipDrawable extends Drawable implements Drawable.Callback {
private ClipState mClipState; private ClipState mState;
private final Rect mTmpRect = new Rect(); private final Rect mTmpRect = new Rect();
public static final int HORIZONTAL = 1; public static final int HORIZONTAL = 1;
@@ -67,9 +69,9 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
public ClipDrawable(Drawable drawable, int gravity, int orientation) { public ClipDrawable(Drawable drawable, int gravity, int orientation) {
this(null, null); this(null, null);
mClipState.mDrawable = drawable; mState.mDrawable = drawable;
mClipState.mGravity = gravity; mState.mGravity = gravity;
mClipState.mOrientation = orientation; mState.mOrientation = orientation;
if (drawable != null) { if (drawable != null) {
drawable.setCallback(this); drawable.setCallback(this);
@@ -81,19 +83,22 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs, theme); super.inflate(r, parser, attrs, theme);
int type; final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ClipDrawable);
TypedArray a = obtainAttributes( // Reset mDrawable to preserve old multiple-inflate behavior. This is
r, theme, attrs, com.android.internal.R.styleable.ClipDrawable); // silly, but we have CTS tests that rely on it.
mState.mDrawable = null;
int orientation = a.getInt(
com.android.internal.R.styleable.ClipDrawable_clipOrientation,
HORIZONTAL);
int g = a.getInt(com.android.internal.R.styleable.ClipDrawable_gravity, Gravity.LEFT);
Drawable dr = a.getDrawable(com.android.internal.R.styleable.ClipDrawable_drawable);
updateStateFromTypedArray(a);
inflateChildElements(r, parser, attrs, theme);
verifyRequiredAttributes(a);
a.recycle(); a.recycle();
}
private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
Theme theme) throws XmlPullParserException, IOException {
Drawable dr = null;
int type;
final int outerDepth = parser.getDepth(); final int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
@@ -103,35 +108,68 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
dr = Drawable.createFromXmlInner(r, parser, attrs, theme); dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
} }
if (dr == null) { if (dr != null) {
throw new IllegalArgumentException("No drawable specified for <clip>"); mState.mDrawable = dr;
dr.setCallback(this);
} }
}
mClipState.mDrawable = dr; private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
mClipState.mOrientation = orientation; // If we're not waiting on a theme, verify required attributes.
mClipState.mGravity = g; if (mState.mDrawable == 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");
}
}
dr.setCallback(this); private void updateStateFromTypedArray(TypedArray a) {
final ClipState state = mState;
// 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);
final Drawable dr = a.getDrawable(R.styleable.ClipDrawable_drawable);
if (dr != null) {
state.mDrawable = dr;
dr.setCallback(this);
}
} }
@Override @Override
public void applyTheme(Theme t) { public void applyTheme(Theme t) {
super.applyTheme(t); super.applyTheme(t);
final ClipState state = mClipState; final ClipState state = mState;
if (state == null) { if (state == null) {
return; return;
} }
if (state.mDrawable != null) { final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ClipDrawable);
try {
updateStateFromTypedArray(a);
verifyRequiredAttributes(a);
} catch (XmlPullParserException e) {
throw new RuntimeException(e);
} finally {
a.recycle();
}
if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
state.mDrawable.applyTheme(t); state.mDrawable.applyTheme(t);
} }
} }
@Override @Override
public boolean canApplyTheme() { public boolean canApplyTheme() {
final ClipState state = mClipState; return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme();
} }
// overrides from Drawable.Callback // overrides from Drawable.Callback
@@ -165,78 +203,78 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
@Override @Override
public int getChangingConfigurations() { public int getChangingConfigurations() {
return super.getChangingConfigurations() return super.getChangingConfigurations()
| mClipState.mChangingConfigurations | mState.mChangingConfigurations
| mClipState.mDrawable.getChangingConfigurations(); | mState.mDrawable.getChangingConfigurations();
} }
@Override @Override
public boolean getPadding(Rect padding) { public boolean getPadding(Rect padding) {
// XXX need to adjust padding! // XXX need to adjust padding!
return mClipState.mDrawable.getPadding(padding); return mState.mDrawable.getPadding(padding);
} }
@Override @Override
public boolean setVisible(boolean visible, boolean restart) { public boolean setVisible(boolean visible, boolean restart) {
mClipState.mDrawable.setVisible(visible, restart); mState.mDrawable.setVisible(visible, restart);
return super.setVisible(visible, restart); return super.setVisible(visible, restart);
} }
@Override @Override
public void setAlpha(int alpha) { public void setAlpha(int alpha) {
mClipState.mDrawable.setAlpha(alpha); mState.mDrawable.setAlpha(alpha);
} }
@Override @Override
public int getAlpha() { public int getAlpha() {
return mClipState.mDrawable.getAlpha(); return mState.mDrawable.getAlpha();
} }
@Override @Override
public void setColorFilter(ColorFilter cf) { public void setColorFilter(ColorFilter cf) {
mClipState.mDrawable.setColorFilter(cf); mState.mDrawable.setColorFilter(cf);
} }
@Override @Override
public void setTintList(ColorStateList tint) { public void setTintList(ColorStateList tint) {
mClipState.mDrawable.setTintList(tint); mState.mDrawable.setTintList(tint);
} }
@Override @Override
public void setTintMode(Mode tintMode) { public void setTintMode(Mode tintMode) {
mClipState.mDrawable.setTintMode(tintMode); mState.mDrawable.setTintMode(tintMode);
} }
@Override @Override
public int getOpacity() { public int getOpacity() {
return mClipState.mDrawable.getOpacity(); return mState.mDrawable.getOpacity();
} }
@Override @Override
public boolean isStateful() { public boolean isStateful() {
return mClipState.mDrawable.isStateful(); return mState.mDrawable.isStateful();
} }
@Override @Override
protected boolean onStateChange(int[] state) { protected boolean onStateChange(int[] state) {
return mClipState.mDrawable.setState(state); return mState.mDrawable.setState(state);
} }
@Override @Override
protected boolean onLevelChange(int level) { protected boolean onLevelChange(int level) {
mClipState.mDrawable.setLevel(level); mState.mDrawable.setLevel(level);
invalidateSelf(); invalidateSelf();
return true; return true;
} }
@Override @Override
protected void onBoundsChange(Rect bounds) { protected void onBoundsChange(Rect bounds) {
mClipState.mDrawable.setBounds(bounds); mState.mDrawable.setBounds(bounds);
} }
@Override @Override
public void draw(Canvas canvas) { public void draw(Canvas canvas) {
if (mClipState.mDrawable.getLevel() == 0) { if (mState.mDrawable.getLevel() == 0) {
return; return;
} }
@@ -244,41 +282,41 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
final Rect bounds = getBounds(); final Rect bounds = getBounds();
int level = getLevel(); int level = getLevel();
int w = bounds.width(); int w = bounds.width();
final int iw = 0; //mClipState.mDrawable.getIntrinsicWidth(); final int iw = 0; //mState.mDrawable.getIntrinsicWidth();
if ((mClipState.mOrientation & HORIZONTAL) != 0) { if ((mState.mOrientation & HORIZONTAL) != 0) {
w -= (w - iw) * (10000 - level) / 10000; w -= (w - iw) * (10000 - level) / 10000;
} }
int h = bounds.height(); int h = bounds.height();
final int ih = 0; //mClipState.mDrawable.getIntrinsicHeight(); final int ih = 0; //mState.mDrawable.getIntrinsicHeight();
if ((mClipState.mOrientation & VERTICAL) != 0) { if ((mState.mOrientation & VERTICAL) != 0) {
h -= (h - ih) * (10000 - level) / 10000; h -= (h - ih) * (10000 - level) / 10000;
} }
final int layoutDirection = getLayoutDirection(); final int layoutDirection = getLayoutDirection();
Gravity.apply(mClipState.mGravity, w, h, bounds, r, layoutDirection); Gravity.apply(mState.mGravity, w, h, bounds, r, layoutDirection);
if (w > 0 && h > 0) { if (w > 0 && h > 0) {
canvas.save(); canvas.save();
canvas.clipRect(r); canvas.clipRect(r);
mClipState.mDrawable.draw(canvas); mState.mDrawable.draw(canvas);
canvas.restore(); canvas.restore();
} }
} }
@Override @Override
public int getIntrinsicWidth() { public int getIntrinsicWidth() {
return mClipState.mDrawable.getIntrinsicWidth(); return mState.mDrawable.getIntrinsicWidth();
} }
@Override @Override
public int getIntrinsicHeight() { public int getIntrinsicHeight() {
return mClipState.mDrawable.getIntrinsicHeight(); return mState.mDrawable.getIntrinsicHeight();
} }
@Override @Override
public ConstantState getConstantState() { public ConstantState getConstantState() {
if (mClipState.canConstantState()) { if (mState.canConstantState()) {
mClipState.mChangingConfigurations = getChangingConfigurations(); mState.mChangingConfigurations = getChangingConfigurations();
return mClipState; return mState;
} }
return null; return null;
} }
@@ -286,14 +324,14 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
/** @hide */ /** @hide */
@Override @Override
public void setLayoutDirection(int layoutDirection) { public void setLayoutDirection(int layoutDirection) {
mClipState.mDrawable.setLayoutDirection(layoutDirection); mState.mDrawable.setLayoutDirection(layoutDirection);
super.setLayoutDirection(layoutDirection); super.setLayoutDirection(layoutDirection);
} }
@Override @Override
public Drawable mutate() { public Drawable mutate() {
if (!mMutated && super.mutate() == this) { if (!mMutated && super.mutate() == this) {
mClipState.mDrawable.mutate(); mState.mDrawable.mutate();
mMutated = true; mMutated = true;
} }
return this; return this;
@@ -304,21 +342,26 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
*/ */
public void clearMutated() { public void clearMutated() {
super.clearMutated(); super.clearMutated();
mClipState.mDrawable.clearMutated(); mState.mDrawable.clearMutated();
mMutated = false; mMutated = false;
} }
final static class ClipState extends ConstantState { final static class ClipState extends ConstantState {
Drawable mDrawable; int[] mThemeAttrs;
int mChangingConfigurations; int mChangingConfigurations;
int mOrientation;
int mGravity; Drawable mDrawable;
int mOrientation = HORIZONTAL;
int mGravity = Gravity.LEFT;
private boolean mCheckedConstantState; private boolean mCheckedConstantState;
private boolean mCanConstantState; private boolean mCanConstantState;
ClipState(ClipState orig, ClipDrawable owner, Resources res) { ClipState(ClipState orig, ClipDrawable owner, Resources res) {
if (orig != null) { if (orig != null) {
mThemeAttrs = orig.mThemeAttrs;
mChangingConfigurations = orig.mChangingConfigurations;
if (res != null) { if (res != null) {
mDrawable = orig.mDrawable.getConstantState().newDrawable(res); mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
} else { } else {
@@ -334,6 +377,12 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
} }
} }
@Override
public boolean canApplyTheme() {
return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
|| super.canApplyTheme();
}
@Override @Override
public Drawable newDrawable() { public Drawable newDrawable() {
return new ClipDrawable(this, null); return new ClipDrawable(this, null);
@@ -360,7 +409,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
} }
private ClipDrawable(ClipState state, Resources res) { private ClipDrawable(ClipState state, Resources res) {
mClipState = new ClipState(state, this, res); mState = new ClipState(state, this, res);
} }
} }

View File

@@ -600,11 +600,11 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
Drawable[] mDrawables; Drawable[] mDrawables;
int mNumChildren; int mNumChildren;
boolean mVariablePadding; boolean mVariablePadding = false;
boolean mPaddingChecked; boolean mPaddingChecked;
Rect mConstantPadding; Rect mConstantPadding;
boolean mConstantSize; boolean mConstantSize = false;
boolean mComputedConstantSize; boolean mComputedConstantSize;
int mConstantWidth; int mConstantWidth;
int mConstantHeight; int mConstantHeight;
@@ -625,8 +625,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
boolean mMutated; boolean mMutated;
int mLayoutDirection; int mLayoutDirection;
int mEnterFadeDuration; int mEnterFadeDuration = 0;
int mExitFadeDuration; int mExitFadeDuration = 0;
boolean mAutoMirrored; boolean mAutoMirrored;

View File

@@ -1089,7 +1089,7 @@ public class GradientDrawable extends Drawable {
@Override @Override
public boolean canApplyTheme() { public boolean canApplyTheme() {
return super.canApplyTheme() || mGradientState != null && mGradientState.canApplyTheme(); return (mGradientState != null && mGradientState.canApplyTheme()) || super.canApplyTheme();
} }
private void applyThemeChildElements(Theme t) { private void applyThemeChildElements(Theme t) {
@@ -1632,7 +1632,7 @@ public class GradientDrawable extends Drawable {
public boolean canApplyTheme() { public boolean canApplyTheme() {
return mThemeAttrs != null || mAttrSize != null || mAttrGradient != null return mThemeAttrs != null || mAttrSize != null || mAttrGradient != null
|| mAttrSolid != null || mAttrStroke != null || mAttrCorners != null || mAttrSolid != null || mAttrStroke != null || mAttrCorners != null
|| mAttrPadding != null; || mAttrPadding != null || super.canApplyTheme();
} }
@Override @Override

View File

@@ -55,7 +55,8 @@ import java.io.IOException;
public class InsetDrawable extends Drawable implements Drawable.Callback { public class InsetDrawable extends Drawable implements Drawable.Callback {
private final Rect mTmpRect = new Rect(); private final Rect mTmpRect = new Rect();
private InsetState mInsetState; private final InsetState mState;
private boolean mMutated; private boolean mMutated;
/*package*/ InsetDrawable() { /*package*/ InsetDrawable() {
@@ -70,11 +71,11 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {
int insetRight, int insetBottom) { int insetRight, int insetBottom) {
this(null, null); this(null, null);
mInsetState.mDrawable = drawable; mState.mDrawable = drawable;
mInsetState.mInsetLeft = insetLeft; mState.mInsetLeft = insetLeft;
mInsetState.mInsetTop = insetTop; mState.mInsetTop = insetTop;
mInsetState.mInsetRight = insetRight; mState.mInsetRight = insetRight;
mInsetState.mInsetBottom = insetBottom; mState.mInsetBottom = insetBottom;
if (drawable != null) { if (drawable != null) {
drawable.setCallback(this); drawable.setCallback(this);
@@ -87,11 +88,20 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.InsetDrawable); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.InsetDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.InsetDrawable_visible); super.inflateWithAttributes(r, parser, a, R.styleable.InsetDrawable_visible);
mInsetState.mDrawable = null; // Reset mDrawable to preserve old multiple-inflate behavior. This is
updateStateFromTypedArray(a); // silly, but we have CTS tests that rely on it.
mState.mDrawable = null;
updateStateFromTypedArray(a);
inflateChildElements(r, parser, attrs, theme);
verifyRequiredAttributes(a);
a.recycle();
}
private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
Theme theme) throws XmlPullParserException, IOException {
// Load inner XML elements. // Load inner XML elements.
if (mInsetState.mDrawable == null) { if (mState.mDrawable == null) {
int type; int type;
while ((type=parser.next()) == XmlPullParser.TEXT) { while ((type=parser.next()) == XmlPullParser.TEXT) {
} }
@@ -102,26 +112,23 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {
+ "child tag defining a drawable"); + "child tag defining a drawable");
} }
final Drawable dr = Drawable.createFromXmlInner(r, parser, attrs, theme); final Drawable dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
mInsetState.mDrawable = dr; mState.mDrawable = dr;
dr.setCallback(this); dr.setCallback(this);
} }
verifyRequiredAttributes(a);
a.recycle();
} }
private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException { private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
// If we're not waiting on a theme, verify required attributes. // If we're not waiting on a theme, verify required attributes.
if (mInsetState.mDrawable == null && (mInsetState.mThemeAttrs == null if (mState.mDrawable == null && (mState.mThemeAttrs == null
|| mInsetState.mThemeAttrs[R.styleable.InsetDrawable_drawable] == 0)) { || mState.mThemeAttrs[R.styleable.InsetDrawable_drawable] == 0)) {
throw new XmlPullParserException(a.getPositionDescription() + throw new XmlPullParserException(a.getPositionDescription()
": <inset> tag requires a 'drawable' attribute or " + ": <inset> tag requires a 'drawable' attribute or "
+ "child tag defining a drawable"); + "child tag defining a drawable");
} }
} }
private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException { private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
final InsetState state = mInsetState; final InsetState state = mState;
// Account for any configuration changes. // Account for any configuration changes.
state.mChangingConfigurations |= a.getChangingConfigurations(); state.mChangingConfigurations |= a.getChangingConfigurations();
@@ -169,7 +176,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {
public void applyTheme(Theme t) { public void applyTheme(Theme t) {
super.applyTheme(t); super.applyTheme(t);
final InsetState state = mInsetState; final InsetState state = mState;
if (state == null) { if (state == null) {
return; return;
} }
@@ -193,7 +200,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {
@Override @Override
public boolean canApplyTheme() { public boolean canApplyTheme() {
return super.canApplyTheme() || mInsetState != null && mInsetState.canApplyTheme(); return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
} }
@Override @Override
@@ -222,112 +229,112 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {
@Override @Override
public void draw(Canvas canvas) { public void draw(Canvas canvas) {
mInsetState.mDrawable.draw(canvas); mState.mDrawable.draw(canvas);
} }
@Override @Override
public int getChangingConfigurations() { public int getChangingConfigurations() {
return super.getChangingConfigurations() return super.getChangingConfigurations()
| mInsetState.mChangingConfigurations | mState.mChangingConfigurations
| mInsetState.mDrawable.getChangingConfigurations(); | mState.mDrawable.getChangingConfigurations();
} }
@Override @Override
public boolean getPadding(Rect padding) { public boolean getPadding(Rect padding) {
boolean pad = mInsetState.mDrawable.getPadding(padding); boolean pad = mState.mDrawable.getPadding(padding);
padding.left += mInsetState.mInsetLeft; padding.left += mState.mInsetLeft;
padding.right += mInsetState.mInsetRight; padding.right += mState.mInsetRight;
padding.top += mInsetState.mInsetTop; padding.top += mState.mInsetTop;
padding.bottom += mInsetState.mInsetBottom; padding.bottom += mState.mInsetBottom;
return pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight | return pad || (mState.mInsetLeft | mState.mInsetRight |
mInsetState.mInsetTop | mInsetState.mInsetBottom) != 0; mState.mInsetTop | mState.mInsetBottom) != 0;
} }
/** @hide */ /** @hide */
@Override @Override
public Insets getOpticalInsets() { public Insets getOpticalInsets() {
final Insets contentInsets = super.getOpticalInsets(); final Insets contentInsets = super.getOpticalInsets();
return Insets.of(contentInsets.left + mInsetState.mInsetLeft, return Insets.of(contentInsets.left + mState.mInsetLeft,
contentInsets.top + mInsetState.mInsetTop, contentInsets.top + mState.mInsetTop,
contentInsets.right + mInsetState.mInsetRight, contentInsets.right + mState.mInsetRight,
contentInsets.bottom + mInsetState.mInsetBottom); contentInsets.bottom + mState.mInsetBottom);
} }
@Override @Override
public void setHotspot(float x, float y) { public void setHotspot(float x, float y) {
mInsetState.mDrawable.setHotspot(x, y); mState.mDrawable.setHotspot(x, y);
} }
@Override @Override
public void setHotspotBounds(int left, int top, int right, int bottom) { public void setHotspotBounds(int left, int top, int right, int bottom) {
mInsetState.mDrawable.setHotspotBounds(left, top, right, bottom); mState.mDrawable.setHotspotBounds(left, top, right, bottom);
} }
/** @hide */ /** @hide */
@Override @Override
public void getHotspotBounds(Rect outRect) { public void getHotspotBounds(Rect outRect) {
mInsetState.mDrawable.getHotspotBounds(outRect); mState.mDrawable.getHotspotBounds(outRect);
} }
@Override @Override
public boolean setVisible(boolean visible, boolean restart) { public boolean setVisible(boolean visible, boolean restart) {
mInsetState.mDrawable.setVisible(visible, restart); mState.mDrawable.setVisible(visible, restart);
return super.setVisible(visible, restart); return super.setVisible(visible, restart);
} }
@Override @Override
public void setAlpha(int alpha) { public void setAlpha(int alpha) {
mInsetState.mDrawable.setAlpha(alpha); mState.mDrawable.setAlpha(alpha);
} }
@Override @Override
public int getAlpha() { public int getAlpha() {
return mInsetState.mDrawable.getAlpha(); return mState.mDrawable.getAlpha();
} }
@Override @Override
public void setColorFilter(ColorFilter cf) { public void setColorFilter(ColorFilter cf) {
mInsetState.mDrawable.setColorFilter(cf); mState.mDrawable.setColorFilter(cf);
} }
@Override @Override
public void setTintList(ColorStateList tint) { public void setTintList(ColorStateList tint) {
mInsetState.mDrawable.setTintList(tint); mState.mDrawable.setTintList(tint);
} }
@Override @Override
public void setTintMode(Mode tintMode) { public void setTintMode(Mode tintMode) {
mInsetState.mDrawable.setTintMode(tintMode); mState.mDrawable.setTintMode(tintMode);
} }
/** {@hide} */ /** {@hide} */
@Override @Override
public void setLayoutDirection(int layoutDirection) { public void setLayoutDirection(int layoutDirection) {
mInsetState.mDrawable.setLayoutDirection(layoutDirection); mState.mDrawable.setLayoutDirection(layoutDirection);
} }
@Override @Override
public int getOpacity() { public int getOpacity() {
return mInsetState.mDrawable.getOpacity(); return mState.mDrawable.getOpacity();
} }
@Override @Override
public boolean isStateful() { public boolean isStateful() {
return mInsetState.mDrawable.isStateful(); return mState.mDrawable.isStateful();
} }
@Override @Override
protected boolean onStateChange(int[] state) { protected boolean onStateChange(int[] state) {
boolean changed = mInsetState.mDrawable.setState(state); boolean changed = mState.mDrawable.setState(state);
onBoundsChange(getBounds()); onBoundsChange(getBounds());
return changed; return changed;
} }
@Override @Override
protected boolean onLevelChange(int level) { protected boolean onLevelChange(int level) {
return mInsetState.mDrawable.setLevel(level); return mState.mDrawable.setLevel(level);
} }
@Override @Override
@@ -335,36 +342,36 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {
final Rect r = mTmpRect; final Rect r = mTmpRect;
r.set(bounds); r.set(bounds);
r.left += mInsetState.mInsetLeft; r.left += mState.mInsetLeft;
r.top += mInsetState.mInsetTop; r.top += mState.mInsetTop;
r.right -= mInsetState.mInsetRight; r.right -= mState.mInsetRight;
r.bottom -= mInsetState.mInsetBottom; r.bottom -= mState.mInsetBottom;
mInsetState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom); mState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
} }
@Override @Override
public int getIntrinsicWidth() { public int getIntrinsicWidth() {
return mInsetState.mDrawable.getIntrinsicWidth() return mState.mDrawable.getIntrinsicWidth()
+ mInsetState.mInsetLeft + mInsetState.mInsetRight; + mState.mInsetLeft + mState.mInsetRight;
} }
@Override @Override
public int getIntrinsicHeight() { public int getIntrinsicHeight() {
return mInsetState.mDrawable.getIntrinsicHeight() return mState.mDrawable.getIntrinsicHeight()
+ mInsetState.mInsetTop + mInsetState.mInsetBottom; + mState.mInsetTop + mState.mInsetBottom;
} }
@Override @Override
public void getOutline(@NonNull Outline outline) { public void getOutline(@NonNull Outline outline) {
mInsetState.mDrawable.getOutline(outline); mState.mDrawable.getOutline(outline);
} }
@Override @Override
public ConstantState getConstantState() { public ConstantState getConstantState() {
if (mInsetState.canConstantState()) { if (mState.canConstantState()) {
mInsetState.mChangingConfigurations = getChangingConfigurations(); mState.mChangingConfigurations = getChangingConfigurations();
return mInsetState; return mState;
} }
return null; return null;
} }
@@ -372,7 +379,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {
@Override @Override
public Drawable mutate() { public Drawable mutate() {
if (!mMutated && super.mutate() == this) { if (!mMutated && super.mutate() == this) {
mInsetState.mDrawable.mutate(); mState.mDrawable.mutate();
mMutated = true; mMutated = true;
} }
return this; return this;
@@ -383,7 +390,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {
*/ */
public void clearMutated() { public void clearMutated() {
super.clearMutated(); super.clearMutated();
mInsetState.mDrawable.clearMutated(); mState.mDrawable.clearMutated();
mMutated = false; mMutated = false;
} }
@@ -391,7 +398,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {
* Returns the drawable wrapped by this InsetDrawable. May be null. * Returns the drawable wrapped by this InsetDrawable. May be null.
*/ */
public Drawable getDrawable() { public Drawable getDrawable() {
return mInsetState.mDrawable; return mState.mDrawable;
} }
final static class InsetState extends ConstantState { final static class InsetState extends ConstantState {
@@ -400,13 +407,13 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {
Drawable mDrawable; Drawable mDrawable;
int mInsetLeft; int mInsetLeft = 0;
int mInsetTop; int mInsetTop = 0;
int mInsetRight; int mInsetRight = 0;
int mInsetBottom; int mInsetBottom = 0;
boolean mCheckedConstantState; private boolean mCheckedConstantState;
boolean mCanConstantState; private boolean mCanConstantState;
InsetState(InsetState orig, InsetDrawable owner, Resources res) { InsetState(InsetState orig, InsetDrawable owner, Resources res) {
if (orig != null) { if (orig != null) {
@@ -429,6 +436,12 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {
} }
} }
@Override
public boolean canApplyTheme() {
return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
|| super.canApplyTheme();
}
@Override @Override
public Drawable newDrawable() { public Drawable newDrawable() {
return new InsetDrawable(this, null); return new InsetDrawable(this, null);
@@ -444,12 +457,6 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {
return mChangingConfigurations; return mChangingConfigurations;
} }
@Override
public boolean canApplyTheme() {
return super.canApplyTheme() || mThemeAttrs != null
|| mDrawable != null && mDrawable.canApplyTheme();
}
boolean canConstantState() { boolean canConstantState() {
if (!mCheckedConstantState) { if (!mCheckedConstantState) {
mCanConstantState = mDrawable.getConstantState() != null; mCanConstantState = mDrawable.getConstantState() != null;
@@ -461,7 +468,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {
} }
private InsetDrawable(InsetState state, Resources res) { private InsetDrawable(InsetState state, Resources res) {
mInsetState = new InsetState(state, this, res); mState = new InsetState(state, this, res);
} }
} }

View File

@@ -275,7 +275,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
@Override @Override
public boolean canApplyTheme() { public boolean canApplyTheme() {
return super.canApplyTheme() || mLayerState != null && mLayerState.canApplyTheme(); return (mLayerState != null && mLayerState.canApplyTheme()) || super.canApplyTheme();
} }
/** /**
@@ -1020,7 +1020,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
@Override @Override
public boolean canApplyTheme() { public boolean canApplyTheme() {
if (mThemeAttrs != null) { if (mThemeAttrs != null || super.canApplyTheme()) {
return true; return true;
} }

View File

@@ -473,7 +473,7 @@ public class RippleDrawable extends LayerDrawable {
@Override @Override
public boolean canApplyTheme() { public boolean canApplyTheme() {
return super.canApplyTheme() || mState != null && mState.canApplyTheme(); return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
} }
@Override @Override

View File

@@ -31,7 +31,6 @@ import android.content.res.TypedArray;
import android.content.res.Resources.Theme; import android.content.res.Resources.Theme;
import android.util.TypedValue; import android.util.TypedValue;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log;
import java.io.IOException; import java.io.IOException;
@@ -313,6 +312,11 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
return mState.mPivotYRel; return mState.mPivotYRel;
} }
@Override
public boolean canApplyTheme() {
return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
}
@Override @Override
public void invalidateDrawable(Drawable who) { public void invalidateDrawable(Drawable who) {
final Callback callback = getCallback(); final Callback callback = getCallback();
@@ -401,80 +405,17 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
@Override @Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
final TypedArray a = obtainAttributes(r, theme, attrs, final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RotateDrawable);
com.android.internal.R.styleable.RotateDrawable); super.inflateWithAttributes(r, parser, a, R.styleable.RotateDrawable_visible);
super.inflateWithAttributes(r, parser, a, // Reset mDrawable to preserve old multiple-inflate behavior. This is
com.android.internal.R.styleable.RotateDrawable_visible); // silly, but we have CTS tests that rely on it.
mState.mDrawable = null;
TypedValue tv = a.peekValue(com.android.internal.R.styleable.RotateDrawable_pivotX);
final boolean pivotXRel;
final float pivotX;
if (tv == null) {
pivotXRel = true;
pivotX = 0.5f;
} else {
pivotXRel = tv.type == TypedValue.TYPE_FRACTION;
pivotX = pivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
}
tv = a.peekValue(com.android.internal.R.styleable.RotateDrawable_pivotY);
final boolean pivotYRel;
final float pivotY;
if (tv == null) {
pivotYRel = true;
pivotY = 0.5f;
} else {
pivotYRel = tv.type == TypedValue.TYPE_FRACTION;
pivotY = pivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
}
final float fromDegrees = a.getFloat(
com.android.internal.R.styleable.RotateDrawable_fromDegrees, 0.0f);
final float toDegrees = a.getFloat(
com.android.internal.R.styleable.RotateDrawable_toDegrees, 360.0f);
final int res = a.getResourceId(
com.android.internal.R.styleable.RotateDrawable_drawable, 0);
Drawable drawable = null;
if (res > 0) {
drawable = r.getDrawable(res, theme);
}
updateStateFromTypedArray(a);
inflateChildElements(r, parser, attrs, theme);
verifyRequiredAttributes(a);
a.recycle(); a.recycle();
final int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT &&
(type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
if ((drawable = Drawable.createFromXmlInner(r, parser, attrs, theme)) == null) {
Log.w("drawable", "Bad element under <rotate>: "
+ parser .getName());
}
}
if (drawable == null) {
Log.w("drawable", "No drawable specified for <rotate>");
}
final RotateState st = mState;
st.mDrawable = drawable;
st.mPivotXRel = pivotXRel;
st.mPivotX = pivotX;
st.mPivotYRel = pivotYRel;
st.mPivotY = pivotY;
st.mFromDegrees = fromDegrees;
st.mCurrentDegrees = fromDegrees;
st.mToDegrees = toDegrees;
if (drawable != null) {
drawable.setCallback(this);
}
} }
@Override @Override
@@ -486,15 +427,79 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
return; return;
} }
if (state.mDrawable != 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();
}
if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
state.mDrawable.applyTheme(t); state.mDrawable.applyTheme(t);
} }
} }
@Override private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
public boolean canApplyTheme() { Theme theme) throws XmlPullParserException, IOException {
Drawable dr = null;
int type;
final int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
}
if (dr != null) {
mState.mDrawable = dr;
dr.setCallback(this);
}
}
private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
// If we're not waiting on a theme, verify required attributes.
if (mState.mDrawable == null && (mState.mThemeAttrs == null
|| mState.mThemeAttrs[R.styleable.ScaleDrawable_drawable] == 0)) {
throw new XmlPullParserException(a.getPositionDescription()
+ ": <rotate> tag requires a 'drawable' attribute or "
+ "child tag defining a drawable");
}
}
private void updateStateFromTypedArray(TypedArray a) {
final RotateState state = mState; final RotateState state = mState;
return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme();
// Account for any configuration changes.
state.mChangingConfigurations |= a.getChangingConfigurations();
// Extract the theme attributes, if any.
state.mThemeAttrs = a.extractThemeAttrs();
if (a.hasValue(R.styleable.RotateDrawable_pivotX)) {
final TypedValue tv = a.peekValue(R.styleable.RotateDrawable_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.RotateDrawable_pivotY)) {
final TypedValue tv = a.peekValue(R.styleable.RotateDrawable_pivotY);
state.mPivotYRel = tv.type == TypedValue.TYPE_FRACTION;
state.mPivotY = state.mPivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
}
state.mFromDegrees = a.getFloat(R.styleable.RotateDrawable_fromDegrees, state.mFromDegrees);
state.mToDegrees = a.getFloat(R.styleable.RotateDrawable_toDegrees, state.mToDegrees);
final Drawable dr = a.getDrawable(R.styleable.RotateDrawable_drawable);
if (dr != null) {
state.mDrawable = dr;
dr.setCallback(this);
}
} }
@Override @Override
@@ -521,25 +526,28 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
* rotations at the same time. * rotations at the same time.
*/ */
final static class RotateState extends Drawable.ConstantState { final static class RotateState extends Drawable.ConstantState {
Drawable mDrawable; int[] mThemeAttrs;
int mChangingConfigurations; int mChangingConfigurations;
boolean mPivotXRel; Drawable mDrawable;
float mPivotX;
boolean mPivotYRel;
float mPivotY;
float mFromDegrees; boolean mPivotXRel = true;
float mToDegrees; float mPivotX = 0.5f;
boolean mPivotYRel = true;
float mPivotY = 0.5f;
float mCurrentDegrees; float mFromDegrees = 0.0f;
float mToDegrees = 360.0f;
float mCurrentDegrees = 0.0f;
private boolean mCanConstantState;
private boolean mCheckedConstantState; private boolean mCheckedConstantState;
private boolean mCanConstantState;
public RotateState(RotateState orig, RotateDrawable owner, Resources res) { RotateState(RotateState orig, RotateDrawable owner, Resources res) {
if (orig != null) { if (orig != null) {
mThemeAttrs = orig.mThemeAttrs;
mChangingConfigurations = orig.mChangingConfigurations;
if (res != null) { if (res != null) {
mDrawable = orig.mDrawable.getConstantState().newDrawable(res); mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
} else { } else {
@@ -553,12 +561,19 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
mPivotX = orig.mPivotX; mPivotX = orig.mPivotX;
mPivotYRel = orig.mPivotYRel; mPivotYRel = orig.mPivotYRel;
mPivotY = orig.mPivotY; mPivotY = orig.mPivotY;
mFromDegrees = mCurrentDegrees = orig.mFromDegrees; mFromDegrees = orig.mFromDegrees;
mToDegrees = orig.mToDegrees; mToDegrees = orig.mToDegrees;
mCanConstantState = mCheckedConstantState = true; mCurrentDegrees = orig.mCurrentDegrees;
mCheckedConstantState = mCanConstantState = true;
} }
} }
@Override
public boolean canApplyTheme() {
return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
|| super.canApplyTheme();
}
@Override @Override
public Drawable newDrawable() { public Drawable newDrawable() {
return new RotateDrawable(this, null); return new RotateDrawable(this, null);

View File

@@ -16,6 +16,8 @@
package android.graphics.drawable; package android.graphics.drawable;
import com.android.internal.R;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
@@ -47,7 +49,7 @@ import java.io.IOException;
* @attr ref android.R.styleable#ScaleDrawable_drawable * @attr ref android.R.styleable#ScaleDrawable_drawable
*/ */
public class ScaleDrawable extends Drawable implements Drawable.Callback { public class ScaleDrawable extends Drawable implements Drawable.Callback {
private ScaleState mScaleState; private ScaleState mState;
private boolean mMutated; private boolean mMutated;
private final Rect mTmpRect = new Rect(); private final Rect mTmpRect = new Rect();
@@ -58,10 +60,10 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
public ScaleDrawable(Drawable drawable, int gravity, float scaleWidth, float scaleHeight) { public ScaleDrawable(Drawable drawable, int gravity, float scaleWidth, float scaleHeight) {
this(null, null); this(null, null);
mScaleState.mDrawable = drawable; mState.mDrawable = drawable;
mScaleState.mGravity = gravity; mState.mGravity = gravity;
mScaleState.mScaleWidth = scaleWidth; mState.mScaleWidth = scaleWidth;
mScaleState.mScaleHeight = scaleHeight; mState.mScaleHeight = scaleHeight;
if (drawable != null) { if (drawable != null) {
drawable.setCallback(this); drawable.setCallback(this);
@@ -72,18 +74,18 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
* Returns the drawable scaled by this ScaleDrawable. * Returns the drawable scaled by this ScaleDrawable.
*/ */
public Drawable getDrawable() { public Drawable getDrawable() {
return mScaleState.mDrawable; return mState.mDrawable;
} }
private static float getPercent(TypedArray a, int name) { private static float getPercent(TypedArray a, int name, float defaultValue) {
String s = a.getString(name); final String s = a.getString(name);
if (s != null) { if (s != null) {
if (s.endsWith("%")) { if (s.endsWith("%")) {
String f = s.substring(0, s.length() - 1); String f = s.substring(0, s.length() - 1);
return Float.parseFloat(f) / 100.0f; return Float.parseFloat(f) / 100.0f;
} }
} }
return -1; return defaultValue;
} }
@Override @Override
@@ -91,20 +93,48 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs, theme); super.inflate(r, parser, attrs, theme);
int type; final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ScaleDrawable);
TypedArray a = obtainAttributes( // Reset mDrawable to preserve old multiple-inflate behavior. This is
r, theme, attrs, com.android.internal.R.styleable.ScaleDrawable); // silly, but we have CTS tests that rely on it.
mState.mDrawable = null;
float sw = getPercent(a, com.android.internal.R.styleable.ScaleDrawable_scaleWidth);
float sh = getPercent(a, com.android.internal.R.styleable.ScaleDrawable_scaleHeight);
int g = a.getInt(com.android.internal.R.styleable.ScaleDrawable_scaleGravity, Gravity.LEFT);
boolean min = a.getBoolean(
com.android.internal.R.styleable.ScaleDrawable_useIntrinsicSizeAsMinimum, false);
Drawable dr = a.getDrawable(com.android.internal.R.styleable.ScaleDrawable_drawable);
updateStateFromTypedArray(a);
inflateChildElements(r, parser, attrs, theme);
verifyRequiredAttributes(a);
a.recycle(); a.recycle();
}
@Override
public void applyTheme(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();
}
}
if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
state.mDrawable.applyTheme(t);
}
}
private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
Theme theme) throws XmlPullParserException, IOException {
Drawable dr = null;
int type;
final int outerDepth = parser.getDepth(); final int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
@@ -114,38 +144,49 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
dr = Drawable.createFromXmlInner(r, parser, attrs, theme); dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
} }
if (dr == null) {
throw new IllegalArgumentException("No drawable specified for <scale>");
}
mScaleState.mDrawable = dr;
mScaleState.mScaleWidth = sw;
mScaleState.mScaleHeight = sh;
mScaleState.mGravity = g;
mScaleState.mUseIntrinsicSizeAsMin = min;
if (dr != null) { if (dr != null) {
mState.mDrawable = dr;
dr.setCallback(this);
}
}
private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
// If we're not waiting on a theme, verify required attributes.
if (mState.mDrawable == null && (mState.mThemeAttrs == null
|| mState.mThemeAttrs[R.styleable.ScaleDrawable_drawable] == 0)) {
throw new XmlPullParserException(a.getPositionDescription()
+ ": <scale> tag requires a 'drawable' attribute or "
+ "child tag defining a drawable");
}
}
private void updateStateFromTypedArray(TypedArray a) {
final ScaleState state = mState;
// 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, R.styleable.ScaleDrawable_scaleHeight, state.mScaleHeight);
state.mGravity = a.getInt(R.styleable.ScaleDrawable_scaleGravity, Gravity.LEFT);
state.mUseIntrinsicSizeAsMin = a.getBoolean(
R.styleable.ScaleDrawable_useIntrinsicSizeAsMinimum, false);
final Drawable dr = a.getDrawable(R.styleable.ScaleDrawable_drawable);
if (dr != null) {
state.mDrawable = dr;
dr.setCallback(this); dr.setCallback(this);
} }
} }
@Override
public void applyTheme(Theme t) {
super.applyTheme(t);
final ScaleState state = mScaleState;
if (state == null) {
return;
}
if (state.mDrawable != null) {
state.mDrawable.applyTheme(t);
}
}
@Override @Override
public boolean canApplyTheme() { public boolean canApplyTheme() {
final ScaleState state = mScaleState; return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme();
} }
// overrides from Drawable.Callback // overrides from Drawable.Callback
@@ -172,74 +213,74 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
@Override @Override
public void draw(Canvas canvas) { public void draw(Canvas canvas) {
if (mScaleState.mDrawable.getLevel() != 0) if (mState.mDrawable.getLevel() != 0)
mScaleState.mDrawable.draw(canvas); mState.mDrawable.draw(canvas);
} }
@Override @Override
public int getChangingConfigurations() { public int getChangingConfigurations() {
return super.getChangingConfigurations() return super.getChangingConfigurations()
| mScaleState.mChangingConfigurations | mState.mChangingConfigurations
| mScaleState.mDrawable.getChangingConfigurations(); | mState.mDrawable.getChangingConfigurations();
} }
@Override @Override
public boolean getPadding(Rect padding) { public boolean getPadding(Rect padding) {
// XXX need to adjust padding! // XXX need to adjust padding!
return mScaleState.mDrawable.getPadding(padding); return mState.mDrawable.getPadding(padding);
} }
@Override @Override
public boolean setVisible(boolean visible, boolean restart) { public boolean setVisible(boolean visible, boolean restart) {
mScaleState.mDrawable.setVisible(visible, restart); mState.mDrawable.setVisible(visible, restart);
return super.setVisible(visible, restart); return super.setVisible(visible, restart);
} }
@Override @Override
public void setAlpha(int alpha) { public void setAlpha(int alpha) {
mScaleState.mDrawable.setAlpha(alpha); mState.mDrawable.setAlpha(alpha);
} }
@Override @Override
public int getAlpha() { public int getAlpha() {
return mScaleState.mDrawable.getAlpha(); return mState.mDrawable.getAlpha();
} }
@Override @Override
public void setColorFilter(ColorFilter cf) { public void setColorFilter(ColorFilter cf) {
mScaleState.mDrawable.setColorFilter(cf); mState.mDrawable.setColorFilter(cf);
} }
@Override @Override
public void setTintList(ColorStateList tint) { public void setTintList(ColorStateList tint) {
mScaleState.mDrawable.setTintList(tint); mState.mDrawable.setTintList(tint);
} }
@Override @Override
public void setTintMode(Mode tintMode) { public void setTintMode(Mode tintMode) {
mScaleState.mDrawable.setTintMode(tintMode); mState.mDrawable.setTintMode(tintMode);
} }
@Override @Override
public int getOpacity() { public int getOpacity() {
return mScaleState.mDrawable.getOpacity(); return mState.mDrawable.getOpacity();
} }
@Override @Override
public boolean isStateful() { public boolean isStateful() {
return mScaleState.mDrawable.isStateful(); return mState.mDrawable.isStateful();
} }
@Override @Override
protected boolean onStateChange(int[] state) { protected boolean onStateChange(int[] state) {
boolean changed = mScaleState.mDrawable.setState(state); boolean changed = mState.mDrawable.setState(state);
onBoundsChange(getBounds()); onBoundsChange(getBounds());
return changed; return changed;
} }
@Override @Override
protected boolean onLevelChange(int level) { protected boolean onLevelChange(int level) {
mScaleState.mDrawable.setLevel(level); mState.mDrawable.setLevel(level);
onBoundsChange(getBounds()); onBoundsChange(getBounds());
invalidateSelf(); invalidateSelf();
return true; return true;
@@ -248,41 +289,41 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
@Override @Override
protected void onBoundsChange(Rect bounds) { protected void onBoundsChange(Rect bounds) {
final Rect r = mTmpRect; final Rect r = mTmpRect;
final boolean min = mScaleState.mUseIntrinsicSizeAsMin; final boolean min = mState.mUseIntrinsicSizeAsMin;
int level = getLevel(); int level = getLevel();
int w = bounds.width(); int w = bounds.width();
if (mScaleState.mScaleWidth > 0) { if (mState.mScaleWidth > 0) {
final int iw = min ? mScaleState.mDrawable.getIntrinsicWidth() : 0; final int iw = min ? mState.mDrawable.getIntrinsicWidth() : 0;
w -= (int) ((w - iw) * (10000 - level) * mScaleState.mScaleWidth / 10000); w -= (int) ((w - iw) * (10000 - level) * mState.mScaleWidth / 10000);
} }
int h = bounds.height(); int h = bounds.height();
if (mScaleState.mScaleHeight > 0) { if (mState.mScaleHeight > 0) {
final int ih = min ? mScaleState.mDrawable.getIntrinsicHeight() : 0; final int ih = min ? mState.mDrawable.getIntrinsicHeight() : 0;
h -= (int) ((h - ih) * (10000 - level) * mScaleState.mScaleHeight / 10000); h -= (int) ((h - ih) * (10000 - level) * mState.mScaleHeight / 10000);
} }
final int layoutDirection = getLayoutDirection(); final int layoutDirection = getLayoutDirection();
Gravity.apply(mScaleState.mGravity, w, h, bounds, r, layoutDirection); Gravity.apply(mState.mGravity, w, h, bounds, r, layoutDirection);
if (w > 0 && h > 0) { if (w > 0 && h > 0) {
mScaleState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom); mState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
} }
} }
@Override @Override
public int getIntrinsicWidth() { public int getIntrinsicWidth() {
return mScaleState.mDrawable.getIntrinsicWidth(); return mState.mDrawable.getIntrinsicWidth();
} }
@Override @Override
public int getIntrinsicHeight() { public int getIntrinsicHeight() {
return mScaleState.mDrawable.getIntrinsicHeight(); return mState.mDrawable.getIntrinsicHeight();
} }
@Override @Override
public ConstantState getConstantState() { public ConstantState getConstantState() {
if (mScaleState.canConstantState()) { if (mState.canConstantState()) {
mScaleState.mChangingConfigurations = getChangingConfigurations(); mState.mChangingConfigurations = getChangingConfigurations();
return mScaleState; return mState;
} }
return null; return null;
} }
@@ -290,7 +331,7 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
@Override @Override
public Drawable mutate() { public Drawable mutate() {
if (!mMutated && super.mutate() == this) { if (!mMutated && super.mutate() == this) {
mScaleState.mDrawable.mutate(); mState.mDrawable.mutate();
mMutated = true; mMutated = true;
} }
return this; return this;
@@ -301,23 +342,28 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
*/ */
public void clearMutated() { public void clearMutated() {
super.clearMutated(); super.clearMutated();
mScaleState.mDrawable.clearMutated(); mState.mDrawable.clearMutated();
mMutated = false; mMutated = false;
} }
final static class ScaleState extends ConstantState { final static class ScaleState extends ConstantState {
Drawable mDrawable; int[] mThemeAttrs;
int mChangingConfigurations; int mChangingConfigurations;
float mScaleWidth;
float mScaleHeight; Drawable mDrawable;
int mGravity;
boolean mUseIntrinsicSizeAsMin; float mScaleWidth = 1.0f;
float mScaleHeight = 1.0f;
int mGravity = Gravity.LEFT;
boolean mUseIntrinsicSizeAsMin = false;
private boolean mCheckedConstantState; private boolean mCheckedConstantState;
private boolean mCanConstantState; private boolean mCanConstantState;
ScaleState(ScaleState orig, ScaleDrawable owner, Resources res) { ScaleState(ScaleState orig, ScaleDrawable owner, Resources res) {
if (orig != null) { if (orig != null) {
mThemeAttrs = orig.mThemeAttrs;
mChangingConfigurations = orig.mChangingConfigurations;
if (res != null) { if (res != null) {
mDrawable = orig.mDrawable.getConstantState().newDrawable(res); mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
} else { } else {
@@ -335,6 +381,12 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
} }
} }
@Override
public boolean canApplyTheme() {
return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
|| super.canApplyTheme();
}
@Override @Override
public Drawable newDrawable() { public Drawable newDrawable() {
return new ScaleDrawable(this, null); return new ScaleDrawable(this, null);
@@ -361,7 +413,7 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
} }
private ScaleDrawable(ScaleState state, Resources res) { private ScaleDrawable(ScaleState state, Resources res) {
mScaleState = new ScaleState(state, this, res); mState = new ScaleState(state, this, res);
} }
} }

View File

@@ -117,26 +117,48 @@ public class StateListDrawable extends DrawableContainer {
@Override @Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.StateListDrawable); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.StateListDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.StateListDrawable_visible);
super.inflateWithAttributes(r, parser, a, updateStateFromTypedArray(a);
R.styleable.StateListDrawable_visible);
mStateListState.setVariablePadding(a.getBoolean(
R.styleable.StateListDrawable_variablePadding, false));
mStateListState.setConstantSize(a.getBoolean(
R.styleable.StateListDrawable_constantSize, false));
mStateListState.setEnterFadeDuration(a.getInt(
R.styleable.StateListDrawable_enterFadeDuration, 0));
mStateListState.setExitFadeDuration(a.getInt(
R.styleable.StateListDrawable_exitFadeDuration, 0));
setDither(a.getBoolean(R.styleable.StateListDrawable_dither, DEFAULT_DITHER));
setAutoMirrored(a.getBoolean(R.styleable.StateListDrawable_autoMirrored, false));
a.recycle(); a.recycle();
inflateChildElements(r, parser, attrs, theme);
onStateChange(getState());
}
/**
* Updates the constant state from the values in the typed array.
*/
private void updateStateFromTypedArray(TypedArray a) {
final StateListState state = mStateListState;
// Account for any configuration changes.
state.mChangingConfigurations |= a.getChangingConfigurations();
// Extract the theme attributes, if any.
state.mThemeAttrs = a.extractThemeAttrs();
state.mVariablePadding = a.getBoolean(
R.styleable.StateListDrawable_variablePadding, state.mVariablePadding);
state.mConstantSize = a.getBoolean(
R.styleable.StateListDrawable_constantSize, state.mConstantSize);
state.mEnterFadeDuration = a.getInt(
R.styleable.StateListDrawable_enterFadeDuration, state.mEnterFadeDuration);
state.mExitFadeDuration = a.getInt(
R.styleable.StateListDrawable_exitFadeDuration, state.mExitFadeDuration);
state.mDither = a.getBoolean(
R.styleable.StateListDrawable_dither, state.mDither);
state.mAutoMirrored = a.getBoolean(
R.styleable.StateListDrawable_autoMirrored, state.mAutoMirrored);
}
/**
* Inflates child elements from XML.
*/
private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
Theme theme) throws XmlPullParserException, IOException {
final StateListState state = mStateListState;
final int innerDepth = parser.getDepth() + 1; final int innerDepth = parser.getDepth() + 1;
int type; int type;
int depth; int depth;
@@ -185,10 +207,8 @@ public class StateListDrawable extends DrawableContainer {
dr = Drawable.createFromXmlInner(r, parser, attrs, theme); dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
} }
mStateListState.addStateSet(states, dr); state.addStateSet(states, dr);
} }
onStateChange(getState());
} }
StateListState getStateListState() { StateListState getStateListState() {
@@ -282,6 +302,7 @@ public class StateListDrawable extends DrawableContainer {
} }
static class StateListState extends DrawableContainerState { static class StateListState extends DrawableContainerState {
int[] mThemeAttrs;
int[][] mStateSets; int[][] mStateSets;
StateListState(StateListState orig, StateListDrawable owner, Resources res) { StateListState(StateListState orig, StateListDrawable owner, Resources res) {
@@ -298,7 +319,11 @@ public class StateListDrawable extends DrawableContainer {
mStateSets[i] = set.clone(); mStateSets[i] = set.clone();
} }
} }
mThemeAttrs = orig.mThemeAttrs;
mStateSets = Arrays.copyOf(orig.mStateSets, orig.mStateSets.length);
} else { } else {
mThemeAttrs = null;
mStateSets = new int[getCapacity()][]; mStateSets = new int[getCapacity()][];
} }
} }
@@ -330,6 +355,11 @@ public class StateListDrawable extends DrawableContainer {
return new StateListDrawable(this, res); return new StateListDrawable(this, res);
} }
@Override
public boolean canApplyTheme() {
return mThemeAttrs != null || super.canApplyTheme();
}
@Override @Override
public void growArray(int oldSize, int newSize) { public void growArray(int oldSize, int newSize) {
super.growArray(oldSize, newSize); super.growArray(oldSize, newSize);

View File

@@ -361,7 +361,7 @@ public class VectorDrawable extends Drawable {
@Override @Override
public boolean canApplyTheme() { public boolean canApplyTheme() {
return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme(); return (mVectorState != null && mVectorState.canApplyTheme()) || super.canApplyTheme();
} }
@Override @Override
@@ -750,8 +750,8 @@ public class VectorDrawable extends Drawable {
@Override @Override
public boolean canApplyTheme() { public boolean canApplyTheme() {
return super.canApplyTheme() || mThemeAttrs != null return mThemeAttrs != null || (mVPathRenderer != null && mVPathRenderer.canApplyTheme())
|| (mVPathRenderer != null && mVPathRenderer.canApplyTheme()); || super.canApplyTheme();
} }
public VectorDrawableState() { public VectorDrawableState() {