summaryrefslogtreecommitdiffstats
path: root/graphics/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/java/android')
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java157
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java110
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java75
-rw-r--r--graphics/java/android/graphics/drawable/AnimationDrawable.java66
-rw-r--r--graphics/java/android/graphics/drawable/BitmapDrawable.java41
-rw-r--r--graphics/java/android/graphics/drawable/ClipDrawable.java189
-rw-r--r--graphics/java/android/graphics/drawable/ColorDrawable.java27
-rw-r--r--graphics/java/android/graphics/drawable/Drawable.java128
-rw-r--r--graphics/java/android/graphics/drawable/DrawableContainer.java53
-rw-r--r--graphics/java/android/graphics/drawable/GradientDrawable.java135
-rw-r--r--graphics/java/android/graphics/drawable/InsetDrawable.java182
-rw-r--r--graphics/java/android/graphics/drawable/LayerDrawable.java79
-rw-r--r--graphics/java/android/graphics/drawable/LevelListDrawable.java8
-rw-r--r--graphics/java/android/graphics/drawable/NinePatchDrawable.java39
-rw-r--r--graphics/java/android/graphics/drawable/RippleBackground.java19
-rw-r--r--graphics/java/android/graphics/drawable/RippleDrawable.java67
-rw-r--r--graphics/java/android/graphics/drawable/RotateDrawable.java191
-rw-r--r--graphics/java/android/graphics/drawable/ScaleDrawable.java205
-rw-r--r--graphics/java/android/graphics/drawable/ShapeDrawable.java30
-rw-r--r--graphics/java/android/graphics/drawable/StateListDrawable.java90
-rw-r--r--graphics/java/android/graphics/drawable/TransitionDrawable.java19
-rw-r--r--graphics/java/android/graphics/drawable/VectorDrawable.java35
-rw-r--r--graphics/java/android/graphics/pdf/PdfEditor.java159
-rw-r--r--graphics/java/android/graphics/pdf/PdfRenderer.java4
24 files changed, 1397 insertions, 711 deletions
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index 9fb3fb4..d2799e1 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -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;
@@ -186,6 +189,11 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
}
@Override
+ public boolean canApplyTheme() {
+ return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
+ }
+
+ @Override
public void invalidateDrawable(Drawable who) {
final Callback callback = getCallback();
if (callback != null) {
@@ -254,62 +262,112 @@ 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);
+ updateStateFromTypedArray(a);
+ a.recycle();
- 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();
+ inflateChildElements(r, parser, attrs, theme);
- 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();
+ init();
+ }
- setFramesCount(a.getInt(R.styleable.AnimatedRotateDrawable_framesCount, 12));
- setFramesDuration(a.getInt(R.styleable.AnimatedRotateDrawable_frameDuration, 150));
+ @Override
+ public void applyTheme(@Nullable Theme t) {
+ super.applyTheme(t);
- final int res = a.getResourceId(R.styleable.AnimatedRotateDrawable_drawable, 0);
- Drawable drawable = null;
- if (res > 0) {
- drawable = r.getDrawable(res, theme);
+ final AnimatedRotateState state = mState;
+ if (state == null) {
+ return;
}
- a.recycle();
+ 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);
+ }
+ }
+
+ private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
+ Theme theme) throws XmlPullParserException, IOException {
+ final AnimatedRotateState state = mState;
+
+ Drawable dr = null;
int outerDepth = parser.getDepth();
int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT &&
- (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-
+ 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 ((dr = Drawable.createFromXmlInner(r, parser, attrs, theme)) == null) {
+ Log.w(TAG, "Bad element under <animated-rotate>: " + parser.getName());
}
}
- if (drawable == null) {
- Log.w("drawable", "No drawable specified for <animated-rotate>");
+ if (dr != null) {
+ state.mDrawable = dr;
+ dr.setCallback(this);
}
+ }
- final AnimatedRotateState rotateState = mState;
- rotateState.mDrawable = drawable;
- rotateState.mPivotXRel = pivotXRel;
- rotateState.mPivotX = pivotX;
- rotateState.mPivotYRel = pivotYRel;
- rotateState.mPivotY = pivotY;
-
- init();
-
- if (drawable != null) {
- drawable.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");
}
}
@@ -331,17 +389,27 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
return this;
}
+ /**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ mState.mDrawable.clearMutated();
+ mMutated = false;
+ }
+
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;
@@ -358,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;
@@ -379,6 +448,12 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
}
@Override
+ public boolean canApplyTheme() {
+ return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
+ || super.canApplyTheme();
+ }
+
+ @Override
public int getChangingConfigurations() {
return mChangingConfigurations;
}
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index cb09bbf..5a3a617 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -139,27 +139,15 @@ public class AnimatedStateListDrawable extends StateListDrawable {
@Override
protected boolean onStateChange(int[] stateSet) {
- final int keyframeIndex = mState.indexOfKeyframe(stateSet);
- if (keyframeIndex == getCurrentIndex()) {
- // Propagate state change to current keyframe.
- final Drawable current = getCurrent();
- if (current != null) {
- return current.setState(stateSet);
- }
- return false;
- }
-
- // Attempt to find a valid transition to the keyframe.
- if (selectTransition(keyframeIndex)) {
- return true;
- }
-
- // No valid transition, attempt to jump directly to the keyframe.
- if (selectDrawable(keyframeIndex)) {
- return true;
- }
-
- return super.onStateChange(stateSet);
+ // If we're not already at the target index, either attempt to find a
+ // valid transition to it or jump directly there.
+ final int targetIndex = mState.indexOfKeyframe(stateSet);
+ final boolean changedIndex = targetIndex != getCurrentIndex()
+ && (selectTransition(targetIndex) || selectDrawable(targetIndex));
+
+ // Always call super.onStateChanged() to propagate the state change to
+ // the current drawable.
+ return super.onStateChange(stateSet) || changedIndex;
}
private boolean selectTransition(int toIndex) {
@@ -359,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);
+ updateStateFromTypedArray(a);
+ a.recycle();
- 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));
+ inflateChildElements(r, parser, attrs, theme);
- setDither(a.getBoolean(R.styleable.AnimatedStateListDrawable_dither, true));
- setAutoMirrored(a.getBoolean(R.styleable.AnimatedStateListDrawable_autoMirrored, false));
+ init();
+ }
+
+ @Override
+ public void applyTheme(@Nullable Theme theme) {
+ super.applyTheme(theme);
+ final AnimatedStateListState state = mState;
+ if (state == null || state.mAnimThemeAttrs == null) {
+ 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;
@@ -398,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,10 +531,20 @@ public class AnimatedStateListDrawable extends StateListDrawable {
return this;
}
+ /**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ mMutated = false;
+ }
+
static class AnimatedStateListState extends StateListState {
private static final int REVERSE_SHIFT = 32;
private static final int REVERSE_MASK = 0x1;
+ int[] mAnimThemeAttrs;
+
final LongSparseLongArray mTransitions;
final SparseIntArray mStateIds;
@@ -519,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 {
@@ -570,6 +605,11 @@ public class AnimatedStateListDrawable extends StateListDrawable {
}
@Override
+ public boolean canApplyTheme() {
+ return mAnimThemeAttrs != null || super.canApplyTheme();
+ }
+
+ @Override
public Drawable newDrawable() {
return new AnimatedStateListDrawable(this, null);
}
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index ad0b415..e65dbaf 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -16,7 +16,6 @@ package android.graphics.drawable;
import android.animation.Animator;
import android.animation.AnimatorInflater;
-import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -137,15 +136,11 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
private boolean mMutated;
public AnimatedVectorDrawable() {
- mAnimatedVectorState = new AnimatedVectorDrawableState(null);
+ this(null, null);
}
- private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res,
- Theme theme) {
- mAnimatedVectorState = new AnimatedVectorDrawableState(state);
- if (theme != null && canApplyTheme()) {
- applyTheme(theme);
- }
+ private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res) {
+ mAnimatedVectorState = new AnimatedVectorDrawableState(state, mCallback, res);
}
@Override
@@ -157,6 +152,15 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
return this;
}
+ /**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ mAnimatedVectorState.mVectorDrawable.clearMutated();
+ mMutated = false;
+ }
+
@Override
public ConstantState getConstantState() {
mAnimatedVectorState.mChangingConfigurations = getChangingConfigurations();
@@ -281,7 +285,11 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
VectorDrawable vectorDrawable = (VectorDrawable) res.getDrawable(
drawableRes, theme).mutate();
vectorDrawable.setAllowCaching(false);
+ vectorDrawable.setCallback(mCallback);
pathErrorScale = vectorDrawable.getPixelSize();
+ if (mAnimatedVectorState.mVectorDrawable != null) {
+ mAnimatedVectorState.mVectorDrawable.setCallback(null);
+ }
mAnimatedVectorState.mVectorDrawable = vectorDrawable;
}
a.recycle();
@@ -308,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
@@ -329,14 +336,22 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
ArrayList<Animator> mAnimators;
ArrayMap<Animator, String> mTargetNameMap;
- public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy) {
+ public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy,
+ Callback owner, Resources res) {
if (copy != null) {
mChangingConfigurations = copy.mChangingConfigurations;
if (copy.mVectorDrawable != null) {
- mVectorDrawable = (VectorDrawable) copy.mVectorDrawable.getConstantState().newDrawable();
- mVectorDrawable.mutate();
- mVectorDrawable.setAllowCaching(false);
+ final ConstantState cs = copy.mVectorDrawable.getConstantState();
+ if (res != null) {
+ mVectorDrawable = (VectorDrawable) cs.newDrawable(res);
+ } else {
+ mVectorDrawable = (VectorDrawable) cs.newDrawable();
+ }
+ mVectorDrawable = (VectorDrawable) mVectorDrawable.mutate();
+ mVectorDrawable.setCallback(owner);
+ mVectorDrawable.setLayoutDirection(copy.mVectorDrawable.getLayoutDirection());
mVectorDrawable.setBounds(copy.mVectorDrawable.getBounds());
+ mVectorDrawable.setAllowCaching(false);
}
if (copy.mAnimators != null) {
final int numAnimators = copy.mAnimators.size();
@@ -358,18 +373,19 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
}
@Override
- public Drawable newDrawable() {
- return new AnimatedVectorDrawable(this, null, null);
+ public boolean canApplyTheme() {
+ return (mVectorDrawable != null && mVectorDrawable.canApplyTheme())
+ || super.canApplyTheme();
}
@Override
- public Drawable newDrawable(Resources res) {
- return new AnimatedVectorDrawable(this, res, null);
+ public Drawable newDrawable() {
+ return new AnimatedVectorDrawable(this, null);
}
@Override
- public Drawable newDrawable(Resources res, Theme theme) {
- return new AnimatedVectorDrawable(this, res, theme);
+ public Drawable newDrawable(Resources res) {
+ return new AnimatedVectorDrawable(this, res);
}
@Override
@@ -473,4 +489,21 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
}
return true;
}
+
+ private final Callback mCallback = new Callback() {
+ @Override
+ public void invalidateDrawable(Drawable who) {
+ invalidateSelf();
+ }
+
+ @Override
+ public void scheduleDrawable(Drawable who, Runnable what, long when) {
+ scheduleSelf(what, when);
+ }
+
+ @Override
+ public void unscheduleDrawable(Drawable who, Runnable what) {
+ unscheduleSelf(what);
+ }
+ };
}
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 9a9fd82..a8b6c94 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -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 {
+ final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimationDrawable);
+ super.inflateWithAttributes(r, parser, a, R.styleable.AnimationDrawable_visible);
+ updateStateFromTypedArray(a);
+ a.recycle();
- 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);
+ inflateChildElements(r, parser, attrs, theme);
- a.recycle();
+ 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
@@ -347,9 +351,17 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
return this;
}
+ /**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ mMutated = false;
+ }
+
private final static class AnimationState extends DrawableContainerState {
private int[] mDurations;
- private boolean mOneShot;
+ private boolean mOneShot = false;
AnimationState(AnimationState orig, AnimationDrawable owner,
Resources res) {
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index cf6be48..79ac651 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -132,7 +132,7 @@ public class BitmapDrawable extends Drawable {
*/
@Deprecated
public BitmapDrawable(Bitmap bitmap) {
- this(new BitmapState(bitmap), null, null);
+ this(new BitmapState(bitmap), null);
}
/**
@@ -140,7 +140,7 @@ public class BitmapDrawable extends Drawable {
* the display metrics of the resources.
*/
public BitmapDrawable(Resources res, Bitmap bitmap) {
- this(new BitmapState(bitmap), res, null);
+ this(new BitmapState(bitmap), res);
mBitmapState.mTargetDensity = mTargetDensity;
}
@@ -151,7 +151,7 @@ public class BitmapDrawable extends Drawable {
*/
@Deprecated
public BitmapDrawable(String filepath) {
- this(new BitmapState(BitmapFactory.decodeFile(filepath)), null, null);
+ this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
if (mBitmapState.mBitmap == null) {
android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
}
@@ -162,7 +162,7 @@ public class BitmapDrawable extends Drawable {
*/
@SuppressWarnings("unused")
public BitmapDrawable(Resources res, String filepath) {
- this(new BitmapState(BitmapFactory.decodeFile(filepath)), null, null);
+ this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
mBitmapState.mTargetDensity = mTargetDensity;
if (mBitmapState.mBitmap == null) {
android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
@@ -176,7 +176,7 @@ public class BitmapDrawable extends Drawable {
*/
@Deprecated
public BitmapDrawable(java.io.InputStream is) {
- this(new BitmapState(BitmapFactory.decodeStream(is)), null, null);
+ this(new BitmapState(BitmapFactory.decodeStream(is)), null);
if (mBitmapState.mBitmap == null) {
android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
}
@@ -187,7 +187,7 @@ public class BitmapDrawable extends Drawable {
*/
@SuppressWarnings("unused")
public BitmapDrawable(Resources res, java.io.InputStream is) {
- this(new BitmapState(BitmapFactory.decodeStream(is)), null, null);
+ this(new BitmapState(BitmapFactory.decodeStream(is)), null);
mBitmapState.mTargetDensity = mTargetDensity;
if (mBitmapState.mBitmap == null) {
android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
@@ -684,6 +684,14 @@ public class BitmapDrawable extends Drawable {
return this;
}
+ /**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ mMutated = false;
+ }
+
@Override
protected boolean onStateChange(int[] stateSet) {
final BitmapState state = mBitmapState;
@@ -911,17 +919,12 @@ public class BitmapDrawable extends Drawable {
@Override
public Drawable newDrawable() {
- return new BitmapDrawable(this, null, null);
+ return new BitmapDrawable(this, null);
}
@Override
public Drawable newDrawable(Resources res) {
- return new BitmapDrawable(this, res, null);
- }
-
- @Override
- public Drawable newDrawable(Resources res, Theme theme) {
- return new BitmapDrawable(this, res, theme);
+ return new BitmapDrawable(this, res);
}
@Override
@@ -934,16 +937,10 @@ public class BitmapDrawable extends Drawable {
* The one constructor to rule them all. This is called by all public
* constructors to set the state and initialize local properties.
*/
- private BitmapDrawable(BitmapState state, Resources res, Theme theme) {
- if (theme != null && state.canApplyTheme()) {
- // If we need to apply a theme, implicitly mutate.
- mBitmapState = new BitmapState(state);
- applyTheme(theme);
- } else {
- mBitmapState = state;
- }
+ private BitmapDrawable(BitmapState state, Resources res) {
+ mBitmapState = state;
- initializeWithState(state, res);
+ initializeWithState(mBitmapState, res);
}
/**
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 40711cf..e5b2b76 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -16,6 +16,8 @@
package android.graphics.drawable;
+import com.android.internal.R;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -49,12 +51,14 @@ 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;
public static final int VERTICAL = 2;
+ private boolean mMutated;
+
ClipDrawable() {
this(null, null);
}
@@ -65,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);
@@ -79,19 +83,22 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs, theme);
- int type;
-
- TypedArray a = obtainAttributes(
- r, theme, attrs, com.android.internal.R.styleable.ClipDrawable);
+ final TypedArray a = obtainAttributes(r, theme, attrs, 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)) {
@@ -101,15 +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);
+ }
+ }
+
+ 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");
+ }
+ }
+
+ 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 = mState;
+ if (state == null || state.mThemeAttrs == null) {
+ return;
+ }
+
+ 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();
}
- mClipState.mDrawable = dr;
- mClipState.mOrientation = orientation;
- mClipState.mGravity = g;
+ if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
+ state.mDrawable.applyTheme(t);
+ }
+ }
- dr.setCallback(this);
+ @Override
+ public boolean canApplyTheme() {
+ return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
}
// overrides from Drawable.Callback
@@ -143,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;
}
@@ -222,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;
}
@@ -264,21 +324,44 @@ 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) {
+ mState.mDrawable.mutate();
+ mMutated = true;
+ }
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ public void clearMutated() {
+ super.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 {
@@ -295,6 +378,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);
}
@@ -320,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);
}
}
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 1253c46..0f0c844 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -88,6 +88,14 @@ public class ColorDrawable extends Drawable {
return this;
}
+ /**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ mMutated = false;
+ }
+
@Override
public void draw(Canvas canvas) {
final ColorFilter colorFilter = mPaint.getColorFilter();
@@ -291,17 +299,12 @@ public class ColorDrawable extends Drawable {
@Override
public Drawable newDrawable() {
- return new ColorDrawable(this, null, null);
+ return new ColorDrawable(this);
}
@Override
public Drawable newDrawable(Resources res) {
- return new ColorDrawable(this, res, null);
- }
-
- @Override
- public Drawable newDrawable(Resources res, Theme theme) {
- return new ColorDrawable(this, res, theme);
+ return new ColorDrawable(this);
}
@Override
@@ -310,14 +313,8 @@ public class ColorDrawable extends Drawable {
}
}
- private ColorDrawable(ColorState state, Resources res, Theme theme) {
- if (theme != null && state.canApplyTheme()) {
- mColorState = new ColorState(state);
- applyTheme(theme);
- } else {
- mColorState = state;
- }
-
+ private ColorDrawable(ColorState state) {
+ mColorState = state;
mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
}
}
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 9ae788c..1fac5b6 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -917,6 +917,20 @@ public abstract class Drawable {
}
/**
+ * Clears the mutated state, allowing this drawable to be cached and
+ * mutated again.
+ * <p>
+ * This is hidden because only framework drawables can be cached, so
+ * custom drawables don't need to support constant state, mutate(), or
+ * clearMutated().
+ *
+ * @hide
+ */
+ public void clearMutated() {
+ // Default implementation is no-op.
+ }
+
+ /**
* Create a drawable from an inputstream
*/
public static Drawable createFromStream(InputStream is, String srcName) {
@@ -1044,54 +1058,72 @@ public abstract class Drawable {
final Drawable drawable;
final String name = parser.getName();
- if (name.equals("selector")) {
- drawable = new StateListDrawable();
- } else if (name.equals("animated-selector")) {
- drawable = new AnimatedStateListDrawable();
- } else if (name.equals("level-list")) {
- drawable = new LevelListDrawable();
- } else if (name.equals("layer-list")) {
- drawable = new LayerDrawable();
- } else if (name.equals("transition")) {
- drawable = new TransitionDrawable();
- } else if (name.equals("ripple")) {
- drawable = new RippleDrawable();
- } else if (name.equals("color")) {
- drawable = new ColorDrawable();
- } else if (name.equals("shape")) {
- drawable = new GradientDrawable();
- } else if (name.equals("vector")) {
- drawable = new VectorDrawable();
- } else if (name.equals("animated-vector")) {
- drawable = new AnimatedVectorDrawable();
- } else if (name.equals("scale")) {
- drawable = new ScaleDrawable();
- } else if (name.equals("clip")) {
- drawable = new ClipDrawable();
- } else if (name.equals("rotate")) {
- drawable = new RotateDrawable();
- } else if (name.equals("animated-rotate")) {
- drawable = new AnimatedRotateDrawable();
- } else if (name.equals("animation-list")) {
- drawable = new AnimationDrawable();
- } else if (name.equals("inset")) {
- drawable = new InsetDrawable();
- } else if (name.equals("bitmap")) {
- //noinspection deprecation
- drawable = new BitmapDrawable(r);
- if (r != null) {
- ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
- }
- } else if (name.equals("nine-patch")) {
- drawable = new NinePatchDrawable();
- if (r != null) {
- ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
- }
- } else {
- throw new XmlPullParserException(parser.getPositionDescription() +
- ": invalid drawable tag " + name);
- }
+ switch (name) {
+ case "selector":
+ drawable = new StateListDrawable();
+ break;
+ case "animated-selector":
+ drawable = new AnimatedStateListDrawable();
+ break;
+ case "level-list":
+ drawable = new LevelListDrawable();
+ break;
+ case "layer-list":
+ drawable = new LayerDrawable();
+ break;
+ case "transition":
+ drawable = new TransitionDrawable();
+ break;
+ case "ripple":
+ drawable = new RippleDrawable();
+ break;
+ case "color":
+ drawable = new ColorDrawable();
+ break;
+ case "shape":
+ drawable = new GradientDrawable();
+ break;
+ case "vector":
+ drawable = new VectorDrawable();
+ break;
+ case "animated-vector":
+ drawable = new AnimatedVectorDrawable();
+ break;
+ case "scale":
+ drawable = new ScaleDrawable();
+ break;
+ case "clip":
+ drawable = new ClipDrawable();
+ break;
+ case "rotate":
+ drawable = new RotateDrawable();
+ break;
+ case "animated-rotate":
+ drawable = new AnimatedRotateDrawable();
+ break;
+ case "animation-list":
+ drawable = new AnimationDrawable();
+ break;
+ case "inset":
+ drawable = new InsetDrawable();
+ break;
+ case "bitmap":
+ drawable = new BitmapDrawable(r);
+ if (r != null) {
+ ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
+ }
+ break;
+ case "nine-patch":
+ drawable = new NinePatchDrawable();
+ if (r != null) {
+ ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
+ }
+ break;
+ default:
+ throw new XmlPullParserException(parser.getPositionDescription() +
+ ": invalid drawable tag " + name);
+ }
drawable.inflate(r, parser, attrs, theme);
return drawable;
}
@@ -1202,7 +1234,7 @@ public abstract class Drawable {
* implemented for drawables that can have a theme applied.
*/
public Drawable newDrawable(Resources res, Theme theme) {
- return newDrawable();
+ return newDrawable(null);
}
/**
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 4a719fe..326490f 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -574,6 +574,15 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
}
/**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ mDrawableContainerState.clearMutated();
+ mMutated = false;
+ }
+
+ /**
* A ConstantState that can contain several {@link Drawable}s.
*
* This class was made public to enable testing, and its visibility may change in a future
@@ -583,8 +592,6 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
final DrawableContainer mOwner;
final Resources mRes;
- Theme mTheme;
-
SparseArray<ConstantStateFuture> mDrawableFutures;
int mChangingConfigurations;
@@ -593,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;
@@ -618,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;
@@ -792,17 +799,17 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
}
final void applyTheme(Theme theme) {
- // No need to call createAllFutures, since future drawables will
- // apply the theme when they are prepared.
- final int N = mNumChildren;
- final Drawable[] drawables = mDrawables;
- for (int i = 0; i < N; i++) {
- if (drawables[i] != null) {
- drawables[i].applyTheme(theme);
+ if (theme != null) {
+ createAllFutures();
+
+ final int N = mNumChildren;
+ final Drawable[] drawables = mDrawables;
+ for (int i = 0; i < N; i++) {
+ if (drawables[i] != null && drawables[i].canApplyTheme()) {
+ drawables[i].applyTheme(theme);
+ }
}
}
-
- mTheme = theme;
}
@Override
@@ -840,6 +847,18 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
mMutated = true;
}
+ final void clearMutated() {
+ final int N = mNumChildren;
+ final Drawable[] drawables = mDrawables;
+ for (int i = 0; i < N; i++) {
+ if (drawables[i] != null) {
+ drawables[i].clearMutated();
+ }
+ }
+
+ mMutated = false;
+ }
+
/**
* A boolean value indicating whether to use the maximum padding value
* of all frames in the set (false), or to use the padding value of the
@@ -1047,10 +1066,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
final Drawable result;
if (state.mRes == null) {
result = mConstantState.newDrawable();
- } else if (state.mTheme == null) {
- result = mConstantState.newDrawable(state.mRes);
} else {
- result = mConstantState.newDrawable(state.mRes, state.mTheme);
+ result = mConstantState.newDrawable(state.mRes);
}
result.setLayoutDirection(state.mLayoutDirection);
result.setCallback(state.mOwner);
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index cd6297b..1458238 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -29,6 +29,8 @@ import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -134,6 +136,7 @@ public class GradientDrawable extends Drawable {
private Rect mPadding;
private Paint mStrokePaint; // optional, set by the caller
private ColorFilter mColorFilter; // optional, set by the caller
+ private PorterDuffColorFilter mTintFilter;
private int mAlpha = 0xFF; // modified by the caller
private final Path mPath = new Path();
@@ -171,7 +174,7 @@ public class GradientDrawable extends Drawable {
}
public GradientDrawable() {
- this(new GradientState(Orientation.TOP_BOTTOM, null), null);
+ this(new GradientState(Orientation.TOP_BOTTOM, null));
}
/**
@@ -179,7 +182,7 @@ public class GradientDrawable extends Drawable {
* of colors for the gradient.
*/
public GradientDrawable(Orientation orientation, int[] colors) {
- this(new GradientState(orientation, colors), null);
+ this(new GradientState(orientation, colors));
}
@Override
@@ -523,13 +526,15 @@ public class GradientDrawable extends Drawable {
mStrokePaint.getStrokeWidth() > 0;
final boolean haveFill = currFillAlpha > 0;
final GradientState st = mGradientState;
+ final ColorFilter colorFilter = mColorFilter != null ? mColorFilter : mTintFilter;
+
/* we need a layer iff we're drawing both a fill and stroke, and the
stroke is non-opaque, and our shapetype actually supports
fill+stroke. Otherwise we can just draw the stroke (if any) on top
of the fill (if any) without worrying about blending artifacts.
*/
- final boolean useLayer = haveStroke && haveFill && st.mShape != LINE &&
- currStrokeAlpha < 255 && (mAlpha < 255 || mColorFilter != null);
+ final boolean useLayer = haveStroke && haveFill && st.mShape != LINE &&
+ currStrokeAlpha < 255 && (mAlpha < 255 || colorFilter != null);
/* Drawing with a layer is slower than direct drawing, but it
allows us to apply paint effects like alpha and colorfilter to
@@ -544,7 +549,7 @@ public class GradientDrawable extends Drawable {
}
mLayerPaint.setDither(st.mDither);
mLayerPaint.setAlpha(mAlpha);
- mLayerPaint.setColorFilter(mColorFilter);
+ mLayerPaint.setColorFilter(colorFilter);
float rad = mStrokePaint.getStrokeWidth();
canvas.saveLayer(mRect.left - rad, mRect.top - rad,
@@ -561,14 +566,14 @@ public class GradientDrawable extends Drawable {
*/
mFillPaint.setAlpha(currFillAlpha);
mFillPaint.setDither(st.mDither);
- mFillPaint.setColorFilter(mColorFilter);
- if (mColorFilter != null && st.mColorStateList == null) {
+ mFillPaint.setColorFilter(colorFilter);
+ if (colorFilter != null && st.mColorStateList == null) {
mFillPaint.setColor(mAlpha << 24);
}
if (haveStroke) {
mStrokePaint.setAlpha(currStrokeAlpha);
mStrokePaint.setDither(st.mDither);
- mStrokePaint.setColorFilter(mColorFilter);
+ mStrokePaint.setColorFilter(colorFilter);
}
}
@@ -593,7 +598,7 @@ public class GradientDrawable extends Drawable {
canvas.drawRoundRect(mRect, rad, rad, mStrokePaint);
}
} else {
- if (mFillPaint.getColor() != 0 || mColorFilter != null ||
+ if (mFillPaint.getColor() != 0 || colorFilter != null ||
mFillPaint.getShader() != null) {
canvas.drawRect(mRect, mFillPaint);
}
@@ -768,6 +773,11 @@ public class GradientDrawable extends Drawable {
}
}
+ if (s.mTint != null && s.mTintMode != null) {
+ mTintFilter = updateTintFilter(mTintFilter, s.mTint, s.mTintMode);
+ invalidateSelf = true;
+ }
+
if (invalidateSelf) {
invalidateSelf();
return true;
@@ -781,7 +791,8 @@ public class GradientDrawable extends Drawable {
final GradientState s = mGradientState;
return super.isStateful()
|| (s.mColorStateList != null && s.mColorStateList.isStateful())
- || (s.mStrokeColorStateList != null && s.mStrokeColorStateList.isStateful());
+ || (s.mStrokeColorStateList != null && s.mStrokeColorStateList.isStateful())
+ || (s.mTint != null && s.mTint.isStateful());
}
@Override
@@ -824,6 +835,20 @@ public class GradientDrawable extends Drawable {
}
@Override
+ public void setTintList(ColorStateList tint) {
+ mGradientState.mTint = tint;
+ mTintFilter = updateTintFilter(mTintFilter, tint, mGradientState.mTintMode);
+ invalidateSelf();
+ }
+
+ @Override
+ public void setTintMode(PorterDuff.Mode tintMode) {
+ mGradientState.mTintMode = tintMode;
+ mTintFilter = updateTintFilter(mTintFilter, mGradientState.mTint, tintMode);
+ invalidateSelf();
+ }
+
+ @Override
public int getOpacity() {
return (mAlpha == 255 && mGradientState.mOpaqueOverBounds && isOpaqueForState()) ?
PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT;
@@ -997,13 +1022,16 @@ public class GradientDrawable extends Drawable {
super.applyTheme(t);
final GradientState state = mGradientState;
- if (state == null || state.mThemeAttrs == null) {
+ if (state == null) {
return;
}
- final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.GradientDrawable);
- updateStateFromTypedArray(a);
- a.recycle();
+ if (state.mThemeAttrs != null) {
+ final TypedArray a = t.resolveAttributes(
+ state.mThemeAttrs, R.styleable.GradientDrawable);
+ updateStateFromTypedArray(a);
+ a.recycle();
+ }
applyThemeChildElements(t);
@@ -1045,15 +1073,23 @@ public class GradientDrawable extends Drawable {
state.mUseLevelForShape = a.getBoolean(
R.styleable.GradientDrawable_useLevel, state.mUseLevelForShape);
}
+
+ final int tintMode = a.getInt(R.styleable.GradientDrawable_tintMode, -1);
+ if (tintMode != -1) {
+ state.mTintMode = Drawable.parseTintMode(tintMode, PorterDuff.Mode.SRC_IN);
+ }
+
+ final ColorStateList tint = a.getColorStateList(R.styleable.GradientDrawable_tint);
+ if (tint != null) {
+ state.mTint = tint;
+ }
+
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
}
@Override
public boolean canApplyTheme() {
- final GradientState st = mGradientState;
- return st != null && (st.mThemeAttrs != null || st.mAttrSize != null
- || st.mAttrGradient != null || st.mAttrSolid != null
- || st.mAttrStroke != null || st.mAttrCorners != null
- || st.mAttrPadding != null);
+ return (mGradientState != null && mGradientState.canApplyTheme()) || super.canApplyTheme();
}
private void applyThemeChildElements(Theme t) {
@@ -1359,9 +1395,12 @@ public class GradientDrawable extends Drawable {
} else {
radiusType = RADIUS_TYPE_FRACTION;
}
- } else {
+ } else if (tv.type == TypedValue.TYPE_DIMENSION) {
radius = tv.getDimension(r.getDisplayMetrics());
radiusType = RADIUS_TYPE_PIXELS;
+ } else {
+ radius = tv.getFloat();
+ radiusType = RADIUS_TYPE_PIXELS;
}
st.mGradientRadius = radius;
@@ -1479,6 +1518,14 @@ public class GradientDrawable extends Drawable {
return this;
}
+ /**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ mMutated = false;
+ }
+
final static class GradientState extends ConstantState {
public int mChangingConfigurations;
public int mShape = RECTANGLE;
@@ -1505,14 +1552,18 @@ public class GradientDrawable extends Drawable {
public int mThickness = -1;
public boolean mDither = false;
- private float mCenterX = 0.5f;
- private float mCenterY = 0.5f;
- private float mGradientRadius = 0.5f;
- private int mGradientRadiusType = RADIUS_TYPE_PIXELS;
- private boolean mUseLevel;
- private boolean mUseLevelForShape;
- private boolean mOpaqueOverBounds;
- private boolean mOpaqueOverShape;
+ float mCenterX = 0.5f;
+ float mCenterY = 0.5f;
+ float mGradientRadius = 0.5f;
+ int mGradientRadiusType = RADIUS_TYPE_PIXELS;
+ boolean mUseLevel = false;
+ boolean mUseLevelForShape = true;
+
+ boolean mOpaqueOverBounds;
+ boolean mOpaqueOverShape;
+
+ ColorStateList mTint = null;
+ PorterDuff.Mode mTintMode = DEFAULT_TINT_MODE;
int[] mThemeAttrs;
int[] mAttrSize;
@@ -1566,6 +1617,8 @@ public class GradientDrawable extends Drawable {
mUseLevelForShape = state.mUseLevelForShape;
mOpaqueOverBounds = state.mOpaqueOverBounds;
mOpaqueOverShape = state.mOpaqueOverShape;
+ mTint = state.mTint;
+ mTintMode = state.mTintMode;
mThemeAttrs = state.mThemeAttrs;
mAttrSize = state.mAttrSize;
mAttrGradient = state.mAttrGradient;
@@ -1577,22 +1630,19 @@ public class GradientDrawable extends Drawable {
@Override
public boolean canApplyTheme() {
- return mThemeAttrs != null;
+ return mThemeAttrs != null || mAttrSize != null || mAttrGradient != null
+ || mAttrSolid != null || mAttrStroke != null || mAttrCorners != null
+ || mAttrPadding != null || super.canApplyTheme();
}
@Override
public Drawable newDrawable() {
- return new GradientDrawable(this, null);
+ return new GradientDrawable(this);
}
@Override
public Drawable newDrawable(Resources res) {
- return new GradientDrawable(this, null);
- }
-
- @Override
- public Drawable newDrawable(Resources res, Theme theme) {
- return new GradientDrawable(this, theme);
+ return new GradientDrawable(this);
}
@Override
@@ -1696,18 +1746,11 @@ public class GradientDrawable extends Drawable {
* The resulting drawable is guaranteed to have a new constant state.
*
* @param state Constant state from which the drawable inherits
- * @param theme Theme to apply to the drawable
*/
- private GradientDrawable(GradientState state, Theme theme) {
- if (theme != null && state.canApplyTheme()) {
- // If we need to apply a theme, implicitly mutate.
- mGradientState = new GradientState(state);
- applyTheme(theme);
- } else {
- mGradientState = state;
- }
+ private GradientDrawable(GradientState state) {
+ mGradientState = state;
- initializeWithState(state);
+ initializeWithState(mGradientState);
mGradientIsDirty = true;
mMutated = false;
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 961d160..b88d9e6 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -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;
+ // 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,25 +176,31 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {
public void applyTheme(Theme t) {
super.applyTheme(t);
- final InsetState state = mInsetState;
- if (state == null || state.mThemeAttrs == null) {
+ final InsetState state = mState;
+ if (state == null) {
return;
}
- final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.InsetDrawable);
- try {
- updateStateFromTypedArray(a);
- verifyRequiredAttributes(a);
- } catch (XmlPullParserException e) {
- throw new RuntimeException(e);
- } finally {
- a.recycle();
+ if (state.mThemeAttrs != null) {
+ final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.InsetDrawable);
+ 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() {
- return mInsetState != null && mInsetState.mThemeAttrs != null;
+ return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
}
@Override
@@ -216,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
@@ -329,34 +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();
+ return mState.mDrawable.getIntrinsicWidth()
+ + mState.mInsetLeft + mState.mInsetRight;
}
@Override
public int getIntrinsicHeight() {
- return mInsetState.mDrawable.getIntrinsicHeight();
+ 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;
}
@@ -364,17 +379,26 @@ 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;
}
/**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ mState.mDrawable.clearMutated();
+ mMutated = false;
+ }
+
+ /**
* 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 {
@@ -383,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) {
@@ -413,6 +437,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);
}
@@ -438,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);
}
}
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 001ed88..689d225 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -100,10 +100,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
* @param state The constant drawable state.
*/
LayerDrawable(Drawable[] layers, LayerState state) {
- this(state, null, null);
- int length = layers.length;
- ChildDrawable[] r = new ChildDrawable[length];
+ this(state, null);
+ final int length = layers.length;
+ final ChildDrawable[] r = new ChildDrawable[length];
for (int i = 0; i < length; i++) {
r[i] = new ChildDrawable();
r[i].mDrawable = layers[i];
@@ -117,18 +117,14 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
}
LayerDrawable() {
- this((LayerState) null, null, null);
+ this((LayerState) null, null);
}
- LayerDrawable(LayerState state, Resources res, Theme theme) {
- final LayerState as = createConstantState(state, res);
- mLayerState = as;
- if (as.mNum > 0) {
+ LayerDrawable(LayerState state, Resources res) {
+ mLayerState = createConstantState(state, res);
+ if (mLayerState.mNum > 0) {
ensurePadding();
}
- if (theme != null && canApplyTheme()) {
- applyTheme(theme);
- }
}
LayerState createConstantState(LayerState state, Resources res) {
@@ -256,8 +252,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
a.recycle();
}
- final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final ChildDrawable[] array = state.mChildren;
+ final int N = state.mNum;
for (int i = 0; i < N; i++) {
final ChildDrawable layer = array[i];
if (layer.mThemeAttrs != null) {
@@ -279,25 +275,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
@Override
public boolean canApplyTheme() {
- final LayerState state = mLayerState;
- if (state == null) {
- return false;
- }
-
- if (state.mThemeAttrs != null) {
- return true;
- }
-
- final ChildDrawable[] array = state.mChildren;
- final int N = state.mNum;
- for (int i = 0; i < N; i++) {
- final ChildDrawable layer = array[i];
- if (layer.mThemeAttrs != null || layer.mDrawable.canApplyTheme()) {
- return true;
- }
- }
-
- return false;
+ return (mLayerState != null && mLayerState.canApplyTheme()) || super.canApplyTheme();
}
/**
@@ -940,6 +918,19 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
return this;
}
+ /**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ final ChildDrawable[] array = mLayerState.mChildren;
+ final int N = mLayerState.mNum;
+ for (int i = 0; i < N; i++) {
+ array[i].mDrawable.clearMutated();
+ }
+ mMutated = false;
+ }
+
/** @hide */
@Override
public void setLayoutDirection(int layoutDirection) {
@@ -1029,22 +1020,30 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
@Override
public boolean canApplyTheme() {
- return mThemeAttrs != null;
+ if (mThemeAttrs != null || super.canApplyTheme()) {
+ return true;
+ }
+
+ final ChildDrawable[] array = mChildren;
+ final int N = mNum;
+ for (int i = 0; i < N; i++) {
+ final ChildDrawable layer = array[i];
+ if (layer.mThemeAttrs != null || layer.mDrawable.canApplyTheme()) {
+ return true;
+ }
+ }
+
+ return false;
}
@Override
public Drawable newDrawable() {
- return new LayerDrawable(this, null, null);
+ return new LayerDrawable(this, null);
}
@Override
public Drawable newDrawable(Resources res) {
- return new LayerDrawable(this, res, null);
- }
-
- @Override
- public Drawable newDrawable(Resources res, Theme theme) {
- return new LayerDrawable(this, res, theme);
+ return new LayerDrawable(this, res);
}
@Override
diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java
index bc1c61d..9e918f6 100644
--- a/graphics/java/android/graphics/drawable/LevelListDrawable.java
+++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java
@@ -153,6 +153,14 @@ public class LevelListDrawable extends DrawableContainer {
return this;
}
+ /**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ mMutated = false;
+ }
+
private final static class LevelListState extends DrawableContainerState {
private int[] mLows;
private int[] mHighs;
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 6c62ccf..d821224 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -90,7 +90,7 @@ public class NinePatchDrawable extends Drawable {
*/
@Deprecated
public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
- this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null, null);
+ this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null);
}
/**
@@ -99,7 +99,7 @@ public class NinePatchDrawable extends Drawable {
*/
public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
Rect padding, String srcName) {
- this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res, null);
+ this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res);
mNinePatchState.mTargetDensity = mTargetDensity;
}
@@ -112,7 +112,7 @@ public class NinePatchDrawable extends Drawable {
public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
Rect padding, Rect opticalInsets, String srcName) {
this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, opticalInsets),
- res, null);
+ res);
mNinePatchState.mTargetDensity = mTargetDensity;
}
@@ -123,7 +123,7 @@ public class NinePatchDrawable extends Drawable {
*/
@Deprecated
public NinePatchDrawable(NinePatch patch) {
- this(new NinePatchState(patch, new Rect()), null, null);
+ this(new NinePatchState(patch, new Rect()), null);
}
/**
@@ -131,7 +131,7 @@ public class NinePatchDrawable extends Drawable {
* based on the display metrics of the resources.
*/
public NinePatchDrawable(Resources res, NinePatch patch) {
- this(new NinePatchState(patch, new Rect()), res, null);
+ this(new NinePatchState(patch, new Rect()), res);
mNinePatchState.mTargetDensity = mTargetDensity;
}
@@ -563,6 +563,14 @@ public class NinePatchDrawable extends Drawable {
return this;
}
+ /**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ mMutated = false;
+ }
+
@Override
protected boolean onStateChange(int[] stateSet) {
final NinePatchState state = mNinePatchState;
@@ -646,17 +654,12 @@ public class NinePatchDrawable extends Drawable {
@Override
public Drawable newDrawable() {
- return new NinePatchDrawable(this, null, null);
+ return new NinePatchDrawable(this, null);
}
@Override
public Drawable newDrawable(Resources res) {
- return new NinePatchDrawable(this, res, null);
- }
-
- @Override
- public Drawable newDrawable(Resources res, Theme theme) {
- return new NinePatchDrawable(this, res, theme);
+ return new NinePatchDrawable(this, res);
}
@Override
@@ -669,16 +672,10 @@ public class NinePatchDrawable extends Drawable {
* The one constructor to rule them all. This is called by all public
* constructors to set the state and initialize local properties.
*/
- private NinePatchDrawable(NinePatchState state, Resources res, Theme theme) {
- if (theme != null && state.canApplyTheme()) {
- // If we need to apply a theme, implicitly mutate.
- mNinePatchState = new NinePatchState(state);
- applyTheme(theme);
- } else {
- mNinePatchState = state;
- }
+ private NinePatchDrawable(NinePatchState state, Resources res) {
+ mNinePatchState = state;
- initializeWithState(state, res);
+ initializeWithState(mNinePatchState, res);
}
/**
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index faa89bf..21d865f 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -43,10 +43,12 @@ class RippleBackground {
private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED;
private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MAX = 4.5f * GLOBAL_SPEED;
private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MIN = 1.5f * GLOBAL_SPEED;
- private static final float WAVE_OUTER_OPACITY_ENTER_VELOCITY = 10.0f * GLOBAL_SPEED;
private static final float WAVE_OUTER_SIZE_INFLUENCE_MAX = 200f;
private static final float WAVE_OUTER_SIZE_INFLUENCE_MIN = 40f;
+ private static final int ENTER_DURATION = 667;
+ private static final int ENTER_DURATION_FAST = 100;
+
// Hardware animators.
private final ArrayList<RenderNodeAnimator> mRunningAnimations =
new ArrayList<RenderNodeAnimator>();
@@ -224,21 +226,20 @@ class RippleBackground {
/**
* Starts the enter animation.
*/
- public void enter() {
+ public void enter(boolean fast) {
cancel();
- final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_ENTER_VELOCITY);
- final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1);
- outer.setAutoCancel(true);
- outer.setDuration(outerDuration);
- outer.setInterpolator(LINEAR_INTERPOLATOR);
+ final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1);
+ opacity.setAutoCancel(true);
+ opacity.setDuration(fast ? ENTER_DURATION_FAST : ENTER_DURATION);
+ opacity.setInterpolator(LINEAR_INTERPOLATOR);
- mAnimOuterOpacity = outer;
+ mAnimOuterOpacity = opacity;
// Enter animations always run on the UI thread, since it's unlikely
// that anything interesting is happening until the user lifts their
// finger.
- outer.start();
+ opacity.start();
}
/**
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index c7aa98e..e658279 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -167,7 +167,7 @@ public class RippleDrawable extends LayerDrawable {
* Constructor used for drawable inflation.
*/
RippleDrawable() {
- this(new RippleState(null, null, null), null, null);
+ this(new RippleState(null, null, null), null);
}
/**
@@ -180,7 +180,7 @@ public class RippleDrawable extends LayerDrawable {
*/
public RippleDrawable(@NonNull ColorStateList color, @Nullable Drawable content,
@Nullable Drawable mask) {
- this(new RippleState(null, null, null), null, null);
+ this(new RippleState(null, null, null), null);
if (color == null) {
throw new IllegalArgumentException("RippleDrawable requires a non-null color");
@@ -280,7 +280,7 @@ public class RippleDrawable extends LayerDrawable {
}
setRippleActive(enabled && pressed);
- setBackgroundActive(focused || (enabled && pressed));
+ setBackgroundActive(focused || (enabled && pressed), focused);
return changed;
}
@@ -296,11 +296,11 @@ public class RippleDrawable extends LayerDrawable {
}
}
- private void setBackgroundActive(boolean active) {
+ private void setBackgroundActive(boolean active, boolean focused) {
if (mBackgroundActive != active) {
mBackgroundActive = active;
if (active) {
- tryBackgroundEnter();
+ tryBackgroundEnter(focused);
} else {
tryBackgroundExit();
}
@@ -333,8 +333,11 @@ public class RippleDrawable extends LayerDrawable {
}
if (mBackgroundActive) {
- tryBackgroundEnter();
+ tryBackgroundEnter(false);
}
+
+ // Skip animations, just show the correct final states.
+ jumpToCurrentState();
}
return changed;
@@ -470,7 +473,7 @@ public class RippleDrawable extends LayerDrawable {
@Override
public boolean canApplyTheme() {
- return super.canApplyTheme() || mState != null && mState.mTouchThemeAttrs != null;
+ return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
}
@Override
@@ -489,14 +492,14 @@ public class RippleDrawable extends LayerDrawable {
/**
* Creates an active hotspot at the specified location.
*/
- private void tryBackgroundEnter() {
+ private void tryBackgroundEnter(boolean focused) {
if (mBackground == null) {
mBackground = new RippleBackground(this, mHotspotBounds);
}
final int color = mState.mColor.getColorForState(getState(), Color.TRANSPARENT);
mBackground.setup(mState.mMaxRadius, color, mDensity);
- mBackground.enter();
+ mBackground.enter(focused);
}
private void tryBackgroundExit() {
@@ -715,10 +718,12 @@ public class RippleDrawable extends LayerDrawable {
final ChildDrawable[] array = mLayerState.mChildren;
final int count = mLayerState.mNum;
- // We don't need a layer if we don't expect to draw any ripples, we have
- // an explicit mask, or if the non-mask content is all opaque.
+ // We don't need a layer if we don't expect to draw any ripples or
+ // a background, we have an explicit mask, or if the non-mask content
+ // is all opaque.
boolean needsLayer = false;
- if ((mExitingRipplesCount > 0 || mBackground != null) && mMask == null) {
+ if ((mExitingRipplesCount > 0 || (mBackground != null && mBackground.shouldDraw()))
+ && mMask == null) {
for (int i = 0; i < count; i++) {
if (array[i].mId != R.id.mask
&& array[i].mDrawable.getOpacity() != PixelFormat.OPAQUE) {
@@ -924,17 +929,12 @@ public class RippleDrawable extends LayerDrawable {
@Override
public Drawable newDrawable() {
- return new RippleDrawable(this, null, null);
+ return new RippleDrawable(this, null);
}
@Override
public Drawable newDrawable(Resources res) {
- return new RippleDrawable(this, res, null);
- }
-
- @Override
- public Drawable newDrawable(Resources res, Theme theme) {
- return new RippleDrawable(this, res, theme);
+ return new RippleDrawable(this, res);
}
}
@@ -968,37 +968,18 @@ public class RippleDrawable extends LayerDrawable {
return mState.mMaxRadius;
}
- private RippleDrawable(RippleState state, Resources res, Theme theme) {
- boolean needsTheme = false;
+ private RippleDrawable(RippleState state, Resources res) {
+ mState = new RippleState(state, this, res);
+ mLayerState = mState;
- final RippleState ns;
- if (theme != null && state != null && state.canApplyTheme()) {
- ns = new RippleState(state, this, res);
- needsTheme = true;
- } else if (state == null) {
- ns = new RippleState(null, this, res);
- } else {
- // We always need a new state since child drawables contain local
- // state but live within the parent's constant state.
- // TODO: Move child drawables into local state.
- ns = new RippleState(state, this, res);
+ if (mState.mNum > 0) {
+ ensurePadding();
}
if (res != null) {
mDensity = res.getDisplayMetrics().density;
}
- mState = ns;
- mLayerState = ns;
-
- if (ns.mNum > 0) {
- ensurePadding();
- }
-
- if (needsTheme) {
- applyTheme(theme);
- }
-
initializeFromState();
}
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 55c9637..3304b33 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -16,6 +16,8 @@
package android.graphics.drawable;
+import com.android.internal.R;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -29,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;
@@ -312,6 +313,11 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
}
@Override
+ public boolean canApplyTheme() {
+ return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
+ }
+
+ @Override
public void invalidateDrawable(Drawable who) {
final Callback callback = getCallback();
if (callback != null) {
@@ -399,79 +405,103 @@ 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);
-
- 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();
- }
+ final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RotateDrawable);
+ super.inflateWithAttributes(r, parser, a, R.styleable.RotateDrawable_visible);
+
+ // 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);
- 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 RotateState state = mState;
+ if (state == null) {
+ return;
}
- 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);
+ if (state.mThemeAttrs != null) {
+ final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.RotateDrawable);
+ try {
+ updateStateFromTypedArray(a);
+ verifyRequiredAttributes(a);
+ } catch (XmlPullParserException e) {
+ throw new RuntimeException(e);
+ } finally {
+ a.recycle();
+ }
+ }
- final int res = a.getResourceId(
- com.android.internal.R.styleable.RotateDrawable_drawable, 0);
- Drawable drawable = null;
- if (res > 0) {
- drawable = r.getDrawable(res, theme);
+ if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
+ state.mDrawable.applyTheme(t);
}
- a.recycle();
+ }
- final int outerDepth = parser.getDepth();
+ private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
+ Theme theme) throws XmlPullParserException, IOException {
+ Drawable dr = null;
int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT &&
- (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-
+ 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 ((drawable = Drawable.createFromXmlInner(r, parser, attrs, theme)) == null) {
- Log.w("drawable", "Bad element under <rotate>: "
- + parser .getName());
- }
+ 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;
- if (drawable == null) {
- Log.w("drawable", "No drawable specified for <rotate>");
+ // 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();
}
- 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);
+ 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);
}
}
@@ -485,30 +515,42 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
}
/**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ mState.mDrawable.clearMutated();
+ mMutated = false;
+ }
+
+ /**
* Represents the state of a rotation for a given drawable. The same
* rotate drawable can be invoked with different states to drive several
* 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 {
@@ -522,13 +564,20 @@ 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);
}
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index b990249..35ef76f 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -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;
-
- TypedArray a = obtainAttributes(
- r, theme, attrs, com.android.internal.R.styleable.ScaleDrawable);
+ final TypedArray a = obtainAttributes(r, theme, attrs, 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,20 +144,51 @@ 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>");
+ if (dr != null) {
+ mState.mDrawable = dr;
+ dr.setCallback(this);
}
+ }
- mScaleState.mDrawable = dr;
- mScaleState.mScaleWidth = sw;
- mScaleState.mScaleHeight = sh;
- mScaleState.mGravity = g;
- mScaleState.mUseIntrinsicSizeAsMin = min;
+ 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 boolean canApplyTheme() {
+ return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
+ }
+
// overrides from Drawable.Callback
public void invalidateDrawable(Drawable who) {
@@ -152,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;
@@ -228,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;
}
@@ -270,25 +331,39 @@ 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;
}
+ /**
+ * @hide
+ */
+ public void clearMutated() {
+ super.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 {
@@ -307,6 +382,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);
}
@@ -332,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);
}
}
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index bd69d76..a3d8c92 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -76,7 +76,7 @@ public class ShapeDrawable extends Drawable {
* ShapeDrawable constructor.
*/
public ShapeDrawable() {
- this(new ShapeState(null), null, null);
+ this(new ShapeState(null), null);
}
/**
@@ -85,7 +85,7 @@ public class ShapeDrawable extends Drawable {
* @param s the Shape that this ShapeDrawable should be
*/
public ShapeDrawable(Shape s) {
- this(new ShapeState(null), null, null);
+ this(new ShapeState(null), null);
mShapeState.mShape = s;
}
@@ -508,6 +508,14 @@ public class ShapeDrawable extends Drawable {
}
/**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ mMutated = false;
+ }
+
+ /**
* Defines the intrinsic properties of this ShapeDrawable's Shape.
*/
final static class ShapeState extends ConstantState {
@@ -547,17 +555,12 @@ public class ShapeDrawable extends Drawable {
@Override
public Drawable newDrawable() {
- return new ShapeDrawable(this, null, null);
+ return new ShapeDrawable(this, null);
}
@Override
public Drawable newDrawable(Resources res) {
- return new ShapeDrawable(this, res, null);
- }
-
- @Override
- public Drawable newDrawable(Resources res, Theme theme) {
- return new ShapeDrawable(this, res, theme);
+ return new ShapeDrawable(this, res);
}
@Override
@@ -570,13 +573,8 @@ public class ShapeDrawable extends Drawable {
* The one constructor to rule them all. This is called by all public
* constructors to set the state and initialize local properties.
*/
- private ShapeDrawable(ShapeState state, Resources res, Theme theme) {
- if (theme != null && state.canApplyTheme()) {
- mShapeState = new ShapeState(state);
- applyTheme(theme);
- } else {
- mShapeState = state;
- }
+ private ShapeDrawable(ShapeState state, Resources res) {
+ mShapeState = state;
initializeWithState(state, res);
}
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 2eb8a80..963943b 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -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);
+ updateStateFromTypedArray(a);
+ a.recycle();
- 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));
+ inflateChildElements(r, parser, attrs, theme);
- setDither(a.getBoolean(R.styleable.StateListDrawable_dither, DEFAULT_DITHER));
- setAutoMirrored(a.getBoolean(R.styleable.StateListDrawable_autoMirrored, false));
+ onStateChange(getState());
+ }
- a.recycle();
+ /**
+ * 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() {
@@ -263,6 +283,14 @@ public class StateListDrawable extends DrawableContainer {
return this;
}
+ /**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ mMutated = false;
+ }
+
/** @hide */
@Override
public void setLayoutDirection(int layoutDirection) {
@@ -274,14 +302,28 @@ public class StateListDrawable extends DrawableContainer {
}
static class StateListState extends DrawableContainerState {
+ int[] mThemeAttrs;
int[][] mStateSets;
StateListState(StateListState orig, StateListDrawable owner, Resources res) {
super(orig, owner, res);
if (orig != null) {
+ // Perform a deep copy.
+ final int[][] sets = orig.mStateSets;
+ final int count = sets.length;
+ mStateSets = new int[count][];
+ for (int i = 0; i < count; i++) {
+ final int[] set = sets[i];
+ if (set != null) {
+ mStateSets[i] = set.clone();
+ }
+ }
+
+ mThemeAttrs = orig.mThemeAttrs;
mStateSets = Arrays.copyOf(orig.mStateSets, orig.mStateSets.length);
} else {
+ mThemeAttrs = null;
mStateSets = new int[getCapacity()][];
}
}
@@ -314,6 +356,11 @@ public class StateListDrawable extends DrawableContainer {
}
@Override
+ public boolean canApplyTheme() {
+ return mThemeAttrs != null || super.canApplyTheme();
+ }
+
+ @Override
public void growArray(int oldSize, int newSize) {
super.growArray(oldSize, newSize);
final int[][] newStateSets = new int[newSize][];
@@ -322,6 +369,13 @@ public class StateListDrawable extends DrawableContainer {
}
}
+ @Override
+ public void applyTheme(Theme theme) {
+ super.applyTheme(theme);
+
+ onStateChange(getState());
+ }
+
void setConstantState(StateListState state) {
super.setConstantState(state);
diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java
index 4380ca4..e5c235e 100644
--- a/graphics/java/android/graphics/drawable/TransitionDrawable.java
+++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java
@@ -17,7 +17,6 @@
package android.graphics.drawable;
import android.content.res.Resources;
-import android.content.res.Resources.Theme;
import android.graphics.Canvas;
import android.os.SystemClock;
@@ -86,11 +85,11 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba
* @see #TransitionDrawable(Drawable[])
*/
TransitionDrawable() {
- this(new TransitionState(null, null, null), null, null);
+ this(new TransitionState(null, null, null), (Resources) null);
}
- private TransitionDrawable(TransitionState state, Resources res, Theme theme) {
- super(state, res, theme);
+ private TransitionDrawable(TransitionState state, Resources res) {
+ super(state, res);
}
private TransitionDrawable(TransitionState state, Drawable[] layers) {
@@ -245,24 +244,18 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba
}
static class TransitionState extends LayerState {
- TransitionState(TransitionState orig, TransitionDrawable owner,
- Resources res) {
+ TransitionState(TransitionState orig, TransitionDrawable owner, Resources res) {
super(orig, owner, res);
}
@Override
public Drawable newDrawable() {
- return new TransitionDrawable(this, null, null);
+ return new TransitionDrawable(this, (Resources) null);
}
@Override
public Drawable newDrawable(Resources res) {
- return new TransitionDrawable(this, res, null);
- }
-
- @Override
- public Drawable newDrawable(Resources res, Theme theme) {
- return new TransitionDrawable(this, res, theme);
+ return new TransitionDrawable(this, res);
}
@Override
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index db0c94f..8b0f635 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -14,6 +14,7 @@
package android.graphics.drawable;
+import android.annotation.NonNull;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
@@ -212,15 +213,8 @@ public class VectorDrawable extends Drawable {
mVectorState = new VectorDrawableState();
}
- private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) {
- if (theme != null && state.canApplyTheme()) {
- // If we need to apply a theme, implicitly mutate.
- mVectorState = new VectorDrawableState(state);
- applyTheme(theme);
- } else {
- mVectorState = state;
- }
-
+ private VectorDrawable(@NonNull VectorDrawableState state) {
+ mVectorState = state;
mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
}
@@ -233,6 +227,14 @@ public class VectorDrawable extends Drawable {
return this;
}
+ /**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ mMutated = false;
+ }
+
Object getTargetByName(String name) {
return mVectorState.mVPathRenderer.mVGTargetsMap.get(name);
}
@@ -359,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
@@ -748,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() {
@@ -758,17 +760,12 @@ public class VectorDrawable extends Drawable {
@Override
public Drawable newDrawable() {
- return new VectorDrawable(this, null, null);
+ return new VectorDrawable(this);
}
@Override
public Drawable newDrawable(Resources res) {
- return new VectorDrawable(this, res, null);
- }
-
- @Override
- public Drawable newDrawable(Resources res, Theme theme) {
- return new VectorDrawable(this, res, theme);
+ return new VectorDrawable(this);
}
@Override
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
index 9837139..2b70b6a 100644
--- a/graphics/java/android/graphics/pdf/PdfEditor.java
+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
@@ -17,6 +17,10 @@
package android.graphics.pdf;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.system.OsConstants;
@@ -55,6 +59,10 @@ public final class PdfEditor {
*
* @param input Seekable file descriptor to read from.
*
+ * @throws java.io.IOException If an error occurs while reading the file.
+ * @throws java.lang.SecurityException If the file requires a password or
+ * the security scheme is not supported.
+ *
* @see #close()
*/
public PdfEditor(@NonNull ParcelFileDescriptor input) throws IOException {
@@ -98,6 +106,109 @@ public final class PdfEditor {
}
/**
+ * Sets a transformation and clip for a given page. The transformation matrix if
+ * non-null must be affine as per {@link android.graphics.Matrix#isAffine()}. If
+ * the clip is null, then no clipping is performed.
+ *
+ * @param pageIndex The page whose transform to set.
+ * @param transform The transformation to apply.
+ * @param clip The clip to apply.
+ */
+ public void setTransformAndClip(int pageIndex, @Nullable Matrix transform,
+ @Nullable Rect clip) {
+ throwIfClosed();
+ throwIfPageNotInDocument(pageIndex);
+ throwIfNotNullAndNotAfine(transform);
+ if (transform == null) {
+ transform = Matrix.IDENTITY_MATRIX;
+ }
+ if (clip == null) {
+ Point size = new Point();
+ getPageSize(pageIndex, size);
+ nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
+ 0, 0, size.x, size.y);
+ } else {
+ nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
+ clip.left, clip.top, clip.right, clip.bottom);
+ }
+ }
+
+ /**
+ * Gets the size of a given page in mils (1/72").
+ *
+ * @param pageIndex The page index.
+ * @param outSize The size output.
+ */
+ public void getPageSize(int pageIndex, @NonNull Point outSize) {
+ throwIfClosed();
+ throwIfOutSizeNull(outSize);
+ throwIfPageNotInDocument(pageIndex);
+ nativeGetPageSize(mNativeDocument, pageIndex, outSize);
+ }
+
+ /**
+ * Gets the media box of a given page in mils (1/72").
+ *
+ * @param pageIndex The page index.
+ * @param outMediaBox The media box output.
+ */
+ public boolean getPageMediaBox(int pageIndex, @NonNull Rect outMediaBox) {
+ throwIfClosed();
+ throwIfOutMediaBoxNull(outMediaBox);
+ throwIfPageNotInDocument(pageIndex);
+ return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox);
+ }
+
+ /**
+ * Sets the media box of a given page in mils (1/72").
+ *
+ * @param pageIndex The page index.
+ * @param mediaBox The media box.
+ */
+ public void setPageMediaBox(int pageIndex, @NonNull Rect mediaBox) {
+ throwIfClosed();
+ throwIfMediaBoxNull(mediaBox);
+ throwIfPageNotInDocument(pageIndex);
+ nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox);
+ }
+
+ /**
+ * Gets the crop box of a given page in mils (1/72").
+ *
+ * @param pageIndex The page index.
+ * @param outCropBox The crop box output.
+ */
+ public boolean getPageCropBox(int pageIndex, @NonNull Rect outCropBox) {
+ throwIfClosed();
+ throwIfOutCropBoxNull(outCropBox);
+ throwIfPageNotInDocument(pageIndex);
+ return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox);
+ }
+
+ /**
+ * Sets the crop box of a given page in mils (1/72").
+ *
+ * @param pageIndex The page index.
+ * @param cropBox The crop box.
+ */
+ public void setPageCropBox(int pageIndex, @NonNull Rect cropBox) {
+ throwIfClosed();
+ throwIfCropBoxNull(cropBox);
+ throwIfPageNotInDocument(pageIndex);
+ nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox);
+ }
+
+ /**
+ * Gets whether the document prefers to be scaled for printing.
+ *
+ * @return Whether to scale the document.
+ */
+ public boolean shouldScaleForPrinting() {
+ throwIfClosed();
+ return nativeScaleForPrinting(mNativeDocument);
+ }
+
+ /**
* Writes the PDF file to the provided destination.
* <p>
* <strong>Note:</strong> This method takes ownership of the passed in file
@@ -154,9 +265,57 @@ public final class PdfEditor {
}
}
+ private void throwIfNotNullAndNotAfine(Matrix matrix) {
+ if (matrix != null && !matrix.isAffine()) {
+ throw new IllegalStateException("Matrix must be afine");
+ }
+ }
+
+ private void throwIfOutSizeNull(Point outSize) {
+ if (outSize == null) {
+ throw new NullPointerException("outSize cannot be null");
+ }
+ }
+
+ private void throwIfOutMediaBoxNull(Rect outMediaBox) {
+ if (outMediaBox == null) {
+ throw new NullPointerException("outMediaBox cannot be null");
+ }
+ }
+
+ private void throwIfMediaBoxNull(Rect mediaBox) {
+ if (mediaBox == null) {
+ throw new NullPointerException("mediaBox cannot be null");
+ }
+ }
+
+ private void throwIfOutCropBoxNull(Rect outCropBox) {
+ if (outCropBox == null) {
+ throw new NullPointerException("outCropBox cannot be null");
+ }
+ }
+
+ private void throwIfCropBoxNull(Rect cropBox) {
+ if (cropBox == null) {
+ throw new NullPointerException("cropBox cannot be null");
+ }
+ }
+
private static native long nativeOpen(int fd, long size);
private static native void nativeClose(long documentPtr);
private static native int nativeGetPageCount(long documentPtr);
private static native int nativeRemovePage(long documentPtr, int pageIndex);
private static native void nativeWrite(long documentPtr, int fd);
+ private static native void nativeSetTransformAndClip(long documentPtr, int pageIndex,
+ long transformPtr, int clipLeft, int clipTop, int clipRight, int clipBottom);
+ private static native void nativeGetPageSize(long documentPtr, int pageIndex, Point outSize);
+ private static native boolean nativeGetPageMediaBox(long documentPtr, int pageIndex,
+ Rect outMediaBox);
+ private static native void nativeSetPageMediaBox(long documentPtr, int pageIndex,
+ Rect mediaBox);
+ private static native boolean nativeGetPageCropBox(long documentPtr, int pageIndex,
+ Rect outMediaBox);
+ private static native void nativeSetPageCropBox(long documentPtr, int pageIndex,
+ Rect mediaBox);
+ private static native boolean nativeScaleForPrinting(long documentPtr);
}
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index 359c294..79934da 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -131,6 +131,10 @@ public final class PdfRenderer implements AutoCloseable {
* </p>
*
* @param input Seekable file descriptor to read from.
+ *
+ * @throws java.io.IOException If an error occurs while reading the file.
+ * @throws java.lang.SecurityException If the file requires a password or
+ * the security scheme is not supported.
*/
public PdfRenderer(@NonNull ParcelFileDescriptor input) throws IOException {
if (input == null) {