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

* commit '07a08010a87daec2091b643a8fcf2f7a27588098':
  Add theme and config change support to more Drawable types
This commit is contained in:
Alan Viverette
2014-10-31 00:14:51 +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;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.ColorFilter;
@@ -41,6 +43,7 @@ import com.android.internal.R;
*/
public class AnimatedRotateDrawable extends Drawable implements Drawable.Callback, Runnable,
Animatable {
private static final String TAG = "AnimatedRotateDrawable";
private AnimatedRotateState mState;
private boolean mMutated;
@@ -185,6 +188,11 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
return mState.mDrawable.getOpacity();
}
@Override
public boolean canApplyTheme() {
return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
}
@Override
public void invalidateDrawable(Drawable who) {
final Callback callback = getCallback();
@@ -254,67 +262,21 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
}
@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.AnimatedRotateDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible);
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);
}
updateStateFromTypedArray(a);
a.recycle();
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 <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;
inflateChildElements(r, parser, attrs, theme);
init();
if (drawable != null) {
drawable.setCallback(this);
}
}
@Override
public void applyTheme(Theme t) {
public void applyTheme(@Nullable Theme t) {
super.applyTheme(t);
final AnimatedRotateState state = mState;
@@ -322,15 +284,91 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
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);
}
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
public boolean canApplyTheme() {
private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
Theme theme) throws XmlPullParserException, IOException {
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) {
@@ -362,15 +400,16 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
final static class AnimatedRotateState extends Drawable.ConstantState {
Drawable mDrawable;
int[] mThemeAttrs;
int mChangingConfigurations;
boolean mPivotXRel;
float mPivotX;
boolean mPivotYRel;
float mPivotY;
int mFrameDuration;
int mFramesCount;
boolean mPivotXRel = false;
float mPivotX = 0;
boolean mPivotYRel = false;
float mPivotY = 0;
int mFrameDuration = 150;
int mFramesCount = 12;
private boolean mCanConstantState;
private boolean mCheckedConstantState;
@@ -387,6 +426,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
mDrawable.setBounds(orig.mDrawable.getBounds());
mDrawable.setLevel(orig.mDrawable.getLevel());
mThemeAttrs = orig.mThemeAttrs;
mPivotXRel = orig.mPivotXRel;
mPivotX = orig.mPivotX;
mPivotYRel = orig.mPivotYRel;
@@ -407,6 +447,12 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
return new AnimatedRotateDrawable(this, res);
}
@Override
public boolean canApplyTheme() {
return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
|| super.canApplyTheme();
}
@Override
public int getChangingConfigurations() {
return mChangingConfigurations;

View File

@@ -347,24 +347,62 @@ public class AnimatedStateListDrawable extends StateListDrawable {
throws XmlPullParserException, IOException {
final TypedArray a = obtainAttributes(
r, theme, attrs, R.styleable.AnimatedStateListDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedStateListDrawable_visible);
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));
updateStateFromTypedArray(a);
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;
final int innerDepth = parser.getDepth() + 1;
@@ -386,8 +424,6 @@ public class AnimatedStateListDrawable extends StateListDrawable {
parseTransition(r, parser, attrs, theme);
}
}
onStateChange(getState());
}
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_MASK = 0x1;
int[] mAnimThemeAttrs;
final LongSparseLongArray mTransitions;
final SparseIntArray mStateIds;
@@ -515,6 +553,7 @@ public class AnimatedStateListDrawable extends StateListDrawable {
super(orig, owner, res);
if (orig != null) {
mAnimThemeAttrs = orig.mAnimThemeAttrs;
mTransitions = orig.mTransitions.clone();
mStateIds = orig.mStateIds.clone();
} else {
@@ -565,6 +604,11 @@ public class AnimatedStateListDrawable extends StateListDrawable {
return (mTransitions.get(keyFromTo, -1) >> REVERSE_SHIFT & REVERSE_MASK) == 1;
}
@Override
public boolean canApplyTheme() {
return mAnimThemeAttrs != null || super.canApplyTheme();
}
@Override
public Drawable newDrawable() {
return new AnimatedStateListDrawable(this, null);

View File

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

View File

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

View File

@@ -16,6 +16,8 @@
package android.graphics.drawable;
import com.android.internal.R;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -49,7 +51,7 @@ import java.io.IOException;
* @attr ref android.R.styleable#ClipDrawable_drawable
*/
public class ClipDrawable extends Drawable implements Drawable.Callback {
private ClipState mClipState;
private ClipState mState;
private final Rect mTmpRect = new Rect();
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) {
this(null, null);
mClipState.mDrawable = drawable;
mClipState.mGravity = gravity;
mClipState.mOrientation = orientation;
mState.mDrawable = drawable;
mState.mGravity = gravity;
mState.mOrientation = orientation;
if (drawable != null) {
drawable.setCallback(this);
@@ -81,19 +83,22 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs, theme);
int type;
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ClipDrawable);
TypedArray a = obtainAttributes(
r, theme, attrs, com.android.internal.R.styleable.ClipDrawable);
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);
// Reset mDrawable to preserve old multiple-inflate behavior. This is
// 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 {
Drawable dr = null;
int type;
final int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (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);
}
if (dr == null) {
throw new IllegalArgumentException("No drawable specified for <clip>");
if (dr != null) {
mState.mDrawable = dr;
dr.setCallback(this);
}
}
mClipState.mDrawable = dr;
mClipState.mOrientation = orientation;
mClipState.mGravity = g;
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.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
public void applyTheme(Theme t) {
super.applyTheme(t);
final ClipState state = mClipState;
final ClipState state = mState;
if (state == null) {
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);
}
}
@Override
public boolean canApplyTheme() {
final ClipState state = mClipState;
return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme();
return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
}
// overrides from Drawable.Callback
@@ -165,78 +203,78 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
@Override
public int getChangingConfigurations() {
return super.getChangingConfigurations()
| mClipState.mChangingConfigurations
| mClipState.mDrawable.getChangingConfigurations();
| mState.mChangingConfigurations
| mState.mDrawable.getChangingConfigurations();
}
@Override
public boolean getPadding(Rect padding) {
// XXX need to adjust padding!
return mClipState.mDrawable.getPadding(padding);
return mState.mDrawable.getPadding(padding);
}
@Override
public boolean setVisible(boolean visible, boolean restart) {
mClipState.mDrawable.setVisible(visible, restart);
mState.mDrawable.setVisible(visible, restart);
return super.setVisible(visible, restart);
}
@Override
public void setAlpha(int alpha) {
mClipState.mDrawable.setAlpha(alpha);
mState.mDrawable.setAlpha(alpha);
}
@Override
public int getAlpha() {
return mClipState.mDrawable.getAlpha();
return mState.mDrawable.getAlpha();
}
@Override
public void setColorFilter(ColorFilter cf) {
mClipState.mDrawable.setColorFilter(cf);
mState.mDrawable.setColorFilter(cf);
}
@Override
public void setTintList(ColorStateList tint) {
mClipState.mDrawable.setTintList(tint);
mState.mDrawable.setTintList(tint);
}
@Override
public void setTintMode(Mode tintMode) {
mClipState.mDrawable.setTintMode(tintMode);
mState.mDrawable.setTintMode(tintMode);
}
@Override
public int getOpacity() {
return mClipState.mDrawable.getOpacity();
return mState.mDrawable.getOpacity();
}
@Override
public boolean isStateful() {
return mClipState.mDrawable.isStateful();
return mState.mDrawable.isStateful();
}
@Override
protected boolean onStateChange(int[] state) {
return mClipState.mDrawable.setState(state);
return mState.mDrawable.setState(state);
}
@Override
protected boolean onLevelChange(int level) {
mClipState.mDrawable.setLevel(level);
mState.mDrawable.setLevel(level);
invalidateSelf();
return true;
}
@Override
protected void onBoundsChange(Rect bounds) {
mClipState.mDrawable.setBounds(bounds);
mState.mDrawable.setBounds(bounds);
}
@Override
public void draw(Canvas canvas) {
if (mClipState.mDrawable.getLevel() == 0) {
if (mState.mDrawable.getLevel() == 0) {
return;
}
@@ -244,41 +282,41 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
final Rect bounds = getBounds();
int level = getLevel();
int w = bounds.width();
final int iw = 0; //mClipState.mDrawable.getIntrinsicWidth();
if ((mClipState.mOrientation & HORIZONTAL) != 0) {
final int iw = 0; //mState.mDrawable.getIntrinsicWidth();
if ((mState.mOrientation & HORIZONTAL) != 0) {
w -= (w - iw) * (10000 - level) / 10000;
}
int h = bounds.height();
final int ih = 0; //mClipState.mDrawable.getIntrinsicHeight();
if ((mClipState.mOrientation & VERTICAL) != 0) {
final int ih = 0; //mState.mDrawable.getIntrinsicHeight();
if ((mState.mOrientation & VERTICAL) != 0) {
h -= (h - ih) * (10000 - level) / 10000;
}
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) {
canvas.save();
canvas.clipRect(r);
mClipState.mDrawable.draw(canvas);
mState.mDrawable.draw(canvas);
canvas.restore();
}
}
@Override
public int getIntrinsicWidth() {
return mClipState.mDrawable.getIntrinsicWidth();
return mState.mDrawable.getIntrinsicWidth();
}
@Override
public int getIntrinsicHeight() {
return mClipState.mDrawable.getIntrinsicHeight();
return mState.mDrawable.getIntrinsicHeight();
}
@Override
public ConstantState getConstantState() {
if (mClipState.canConstantState()) {
mClipState.mChangingConfigurations = getChangingConfigurations();
return mClipState;
if (mState.canConstantState()) {
mState.mChangingConfigurations = getChangingConfigurations();
return mState;
}
return null;
}
@@ -286,14 +324,14 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
/** @hide */
@Override
public void setLayoutDirection(int layoutDirection) {
mClipState.mDrawable.setLayoutDirection(layoutDirection);
mState.mDrawable.setLayoutDirection(layoutDirection);
super.setLayoutDirection(layoutDirection);
}
@Override
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
mClipState.mDrawable.mutate();
mState.mDrawable.mutate();
mMutated = true;
}
return this;
@@ -304,21 +342,26 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
*/
public void clearMutated() {
super.clearMutated();
mClipState.mDrawable.clearMutated();
mState.mDrawable.clearMutated();
mMutated = false;
}
final static class ClipState extends ConstantState {
Drawable mDrawable;
int[] mThemeAttrs;
int mChangingConfigurations;
int mOrientation;
int mGravity;
Drawable mDrawable;
int mOrientation = HORIZONTAL;
int mGravity = Gravity.LEFT;
private boolean mCheckedConstantState;
private boolean mCanConstantState;
ClipState(ClipState orig, ClipDrawable owner, Resources res) {
if (orig != null) {
mThemeAttrs = orig.mThemeAttrs;
mChangingConfigurations = orig.mChangingConfigurations;
if (res != null) {
mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
} 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
public Drawable newDrawable() {
return new ClipDrawable(this, null);
@@ -360,7 +409,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
}
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;
int mNumChildren;
boolean mVariablePadding;
boolean mVariablePadding = false;
boolean mPaddingChecked;
Rect mConstantPadding;
boolean mConstantSize;
boolean mConstantSize = false;
boolean mComputedConstantSize;
int mConstantWidth;
int mConstantHeight;
@@ -625,8 +625,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
boolean mMutated;
int mLayoutDirection;
int mEnterFadeDuration;
int mExitFadeDuration;
int mEnterFadeDuration = 0;
int mExitFadeDuration = 0;
boolean mAutoMirrored;

View File

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

View File

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

View File

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

View File

@@ -31,7 +31,6 @@ import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
import android.util.TypedValue;
import android.util.AttributeSet;
import android.util.Log;
import java.io.IOException;
@@ -313,6 +312,11 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
return mState.mPivotYRel;
}
@Override
public boolean canApplyTheme() {
return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
}
@Override
public void invalidateDrawable(Drawable who) {
final Callback callback = getCallback();
@@ -401,80 +405,17 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException {
final TypedArray a = obtainAttributes(r, theme, attrs,
com.android.internal.R.styleable.RotateDrawable);
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RotateDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.RotateDrawable_visible);
super.inflateWithAttributes(r, parser, a,
com.android.internal.R.styleable.RotateDrawable_visible);
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);
}
// Reset mDrawable to preserve old multiple-inflate behavior. This is
// silly, but we have CTS tests that rely on it.
mState.mDrawable = null;
updateStateFromTypedArray(a);
inflateChildElements(r, parser, attrs, theme);
verifyRequiredAttributes(a);
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
@@ -486,15 +427,79 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
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);
}
}
@Override
public boolean canApplyTheme() {
private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
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;
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
@@ -521,25 +526,28 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
* rotations at the same time.
*/
final static class RotateState extends Drawable.ConstantState {
Drawable mDrawable;
int[] mThemeAttrs;
int mChangingConfigurations;
boolean mPivotXRel;
float mPivotX;
boolean mPivotYRel;
float mPivotY;
Drawable mDrawable;
float mFromDegrees;
float mToDegrees;
boolean mPivotXRel = true;
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 mCanConstantState;
public RotateState(RotateState orig, RotateDrawable owner, Resources res) {
RotateState(RotateState orig, RotateDrawable owner, Resources res) {
if (orig != null) {
mThemeAttrs = orig.mThemeAttrs;
mChangingConfigurations = orig.mChangingConfigurations;
if (res != null) {
mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
} else {
@@ -553,12 +561,19 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
mPivotX = orig.mPivotX;
mPivotYRel = orig.mPivotYRel;
mPivotY = orig.mPivotY;
mFromDegrees = mCurrentDegrees = orig.mFromDegrees;
mFromDegrees = orig.mFromDegrees;
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
public Drawable newDrawable() {
return new RotateDrawable(this, null);

View File

@@ -16,6 +16,8 @@
package android.graphics.drawable;
import com.android.internal.R;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -47,7 +49,7 @@ import java.io.IOException;
* @attr ref android.R.styleable#ScaleDrawable_drawable
*/
public class ScaleDrawable extends Drawable implements Drawable.Callback {
private ScaleState mScaleState;
private ScaleState mState;
private boolean mMutated;
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) {
this(null, null);
mScaleState.mDrawable = drawable;
mScaleState.mGravity = gravity;
mScaleState.mScaleWidth = scaleWidth;
mScaleState.mScaleHeight = scaleHeight;
mState.mDrawable = drawable;
mState.mGravity = gravity;
mState.mScaleWidth = scaleWidth;
mState.mScaleHeight = scaleHeight;
if (drawable != null) {
drawable.setCallback(this);
@@ -72,18 +74,18 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
* Returns the drawable scaled by this ScaleDrawable.
*/
public Drawable getDrawable() {
return mScaleState.mDrawable;
return mState.mDrawable;
}
private static float getPercent(TypedArray a, int name) {
String s = a.getString(name);
private static float getPercent(TypedArray a, int name, float defaultValue) {
final String s = a.getString(name);
if (s != null) {
if (s.endsWith("%")) {
String f = s.substring(0, s.length() - 1);
return Float.parseFloat(f) / 100.0f;
}
}
return -1;
return defaultValue;
}
@Override
@@ -91,20 +93,48 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs, theme);
int type;
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ScaleDrawable);
TypedArray a = obtainAttributes(
r, theme, attrs, com.android.internal.R.styleable.ScaleDrawable);
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);
// Reset mDrawable to preserve old multiple-inflate behavior. This is
// silly, but we have CTS tests that rely on it.
mState.mDrawable = null;
updateStateFromTypedArray(a);
inflateChildElements(r, parser, attrs, theme);
verifyRequiredAttributes(a);
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();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (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);
}
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) {
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);
}
}
@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
public boolean canApplyTheme() {
final ScaleState state = mScaleState;
return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme();
return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
}
// overrides from Drawable.Callback
@@ -172,74 +213,74 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
@Override
public void draw(Canvas canvas) {
if (mScaleState.mDrawable.getLevel() != 0)
mScaleState.mDrawable.draw(canvas);
if (mState.mDrawable.getLevel() != 0)
mState.mDrawable.draw(canvas);
}
@Override
public int getChangingConfigurations() {
return super.getChangingConfigurations()
| mScaleState.mChangingConfigurations
| mScaleState.mDrawable.getChangingConfigurations();
| mState.mChangingConfigurations
| mState.mDrawable.getChangingConfigurations();
}
@Override
public boolean getPadding(Rect padding) {
// XXX need to adjust padding!
return mScaleState.mDrawable.getPadding(padding);
return mState.mDrawable.getPadding(padding);
}
@Override
public boolean setVisible(boolean visible, boolean restart) {
mScaleState.mDrawable.setVisible(visible, restart);
mState.mDrawable.setVisible(visible, restart);
return super.setVisible(visible, restart);
}
@Override
public void setAlpha(int alpha) {
mScaleState.mDrawable.setAlpha(alpha);
mState.mDrawable.setAlpha(alpha);
}
@Override
public int getAlpha() {
return mScaleState.mDrawable.getAlpha();
return mState.mDrawable.getAlpha();
}
@Override
public void setColorFilter(ColorFilter cf) {
mScaleState.mDrawable.setColorFilter(cf);
mState.mDrawable.setColorFilter(cf);
}
@Override
public void setTintList(ColorStateList tint) {
mScaleState.mDrawable.setTintList(tint);
mState.mDrawable.setTintList(tint);
}
@Override
public void setTintMode(Mode tintMode) {
mScaleState.mDrawable.setTintMode(tintMode);
mState.mDrawable.setTintMode(tintMode);
}
@Override
public int getOpacity() {
return mScaleState.mDrawable.getOpacity();
return mState.mDrawable.getOpacity();
}
@Override
public boolean isStateful() {
return mScaleState.mDrawable.isStateful();
return mState.mDrawable.isStateful();
}
@Override
protected boolean onStateChange(int[] state) {
boolean changed = mScaleState.mDrawable.setState(state);
boolean changed = mState.mDrawable.setState(state);
onBoundsChange(getBounds());
return changed;
}
@Override
protected boolean onLevelChange(int level) {
mScaleState.mDrawable.setLevel(level);
mState.mDrawable.setLevel(level);
onBoundsChange(getBounds());
invalidateSelf();
return true;
@@ -248,41 +289,41 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
@Override
protected void onBoundsChange(Rect bounds) {
final Rect r = mTmpRect;
final boolean min = mScaleState.mUseIntrinsicSizeAsMin;
final boolean min = mState.mUseIntrinsicSizeAsMin;
int level = getLevel();
int w = bounds.width();
if (mScaleState.mScaleWidth > 0) {
final int iw = min ? mScaleState.mDrawable.getIntrinsicWidth() : 0;
w -= (int) ((w - iw) * (10000 - level) * mScaleState.mScaleWidth / 10000);
if (mState.mScaleWidth > 0) {
final int iw = min ? mState.mDrawable.getIntrinsicWidth() : 0;
w -= (int) ((w - iw) * (10000 - level) * mState.mScaleWidth / 10000);
}
int h = bounds.height();
if (mScaleState.mScaleHeight > 0) {
final int ih = min ? mScaleState.mDrawable.getIntrinsicHeight() : 0;
h -= (int) ((h - ih) * (10000 - level) * mScaleState.mScaleHeight / 10000);
if (mState.mScaleHeight > 0) {
final int ih = min ? mState.mDrawable.getIntrinsicHeight() : 0;
h -= (int) ((h - ih) * (10000 - level) * mState.mScaleHeight / 10000);
}
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) {
mScaleState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
mState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
}
}
@Override
public int getIntrinsicWidth() {
return mScaleState.mDrawable.getIntrinsicWidth();
return mState.mDrawable.getIntrinsicWidth();
}
@Override
public int getIntrinsicHeight() {
return mScaleState.mDrawable.getIntrinsicHeight();
return mState.mDrawable.getIntrinsicHeight();
}
@Override
public ConstantState getConstantState() {
if (mScaleState.canConstantState()) {
mScaleState.mChangingConfigurations = getChangingConfigurations();
return mScaleState;
if (mState.canConstantState()) {
mState.mChangingConfigurations = getChangingConfigurations();
return mState;
}
return null;
}
@@ -290,7 +331,7 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
@Override
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
mScaleState.mDrawable.mutate();
mState.mDrawable.mutate();
mMutated = true;
}
return this;
@@ -301,23 +342,28 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
*/
public void clearMutated() {
super.clearMutated();
mScaleState.mDrawable.clearMutated();
mState.mDrawable.clearMutated();
mMutated = false;
}
final static class ScaleState extends ConstantState {
Drawable mDrawable;
int[] mThemeAttrs;
int mChangingConfigurations;
float mScaleWidth;
float mScaleHeight;
int mGravity;
boolean mUseIntrinsicSizeAsMin;
Drawable mDrawable;
float mScaleWidth = 1.0f;
float mScaleHeight = 1.0f;
int mGravity = Gravity.LEFT;
boolean mUseIntrinsicSizeAsMin = false;
private boolean mCheckedConstantState;
private boolean mCanConstantState;
ScaleState(ScaleState orig, ScaleDrawable owner, Resources res) {
if (orig != null) {
mThemeAttrs = orig.mThemeAttrs;
mChangingConfigurations = orig.mChangingConfigurations;
if (res != null) {
mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
} 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
public Drawable newDrawable() {
return new ScaleDrawable(this, null);
@@ -361,7 +413,7 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
}
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
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException {
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.StateListDrawable);
super.inflateWithAttributes(r, parser, 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));
super.inflateWithAttributes(r, parser, a, R.styleable.StateListDrawable_visible);
updateStateFromTypedArray(a);
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;
int type;
int depth;
@@ -185,10 +207,8 @@ public class StateListDrawable extends DrawableContainer {
dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
}
mStateListState.addStateSet(states, dr);
state.addStateSet(states, dr);
}
onStateChange(getState());
}
StateListState getStateListState() {
@@ -282,6 +302,7 @@ public class StateListDrawable extends DrawableContainer {
}
static class StateListState extends DrawableContainerState {
int[] mThemeAttrs;
int[][] mStateSets;
StateListState(StateListState orig, StateListDrawable owner, Resources res) {
@@ -298,7 +319,11 @@ public class StateListDrawable extends DrawableContainer {
mStateSets[i] = set.clone();
}
}
mThemeAttrs = orig.mThemeAttrs;
mStateSets = Arrays.copyOf(orig.mStateSets, orig.mStateSets.length);
} else {
mThemeAttrs = null;
mStateSets = new int[getCapacity()][];
}
}
@@ -330,6 +355,11 @@ public class StateListDrawable extends DrawableContainer {
return new StateListDrawable(this, res);
}
@Override
public boolean canApplyTheme() {
return mThemeAttrs != null || super.canApplyTheme();
}
@Override
public void growArray(int oldSize, int newSize) {
super.growArray(oldSize, newSize);

View File

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