summaryrefslogtreecommitdiffstats
path: root/graphics
diff options
context:
space:
mode:
authorAlan Viverette <alanv@google.com>2015-05-15 10:43:12 -0700
committerAlan Viverette <alanv@google.com>2015-05-15 10:54:11 -0700
commit9b115a9870a184e32bdbd07f792f9b8c956c75ca (patch)
tree5f966209b5c84781e9d40f34168514ad8a2f2b75 /graphics
parent79d0c080a060b340e87d9211f5b174613b67d947 (diff)
downloadframeworks_base-9b115a9870a184e32bdbd07f792f9b8c956c75ca.zip
frameworks_base-9b115a9870a184e32bdbd07f792f9b8c956c75ca.tar.gz
frameworks_base-9b115a9870a184e32bdbd07f792f9b8c956c75ca.tar.bz2
Postpone AnimatedVectorDrawable animator inflation until applyTheme()
This CL works around Animator's lack of support for applying a theme after inflation by postponing Animator inflation until a theme is available, either in inflate() or applyTheme(). Includes a workaround for AVDs that don't reference any theme attrs in their animators and this don't require a call to applyTheme(). We'll follow up with real support for applyTheme() in Animator, at which point we can remove this workaround. Bug: 20817800 Change-Id: I5a378a76e3625b9d754cb74ae98c07ba7c5698e5
Diffstat (limited to 'graphics')
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java119
1 files changed, 106 insertions, 13 deletions
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 28c26ff..ea60040 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -19,6 +19,7 @@ import android.animation.AnimatorInflater;
import android.animation.AnimatorSet;
import android.animation.Animator.AnimatorListener;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
@@ -127,13 +128,19 @@ import java.util.List;
* @attr ref android.R.styleable#AnimatedVectorDrawableTarget_animation
*/
public class AnimatedVectorDrawable extends Drawable implements Animatable {
- private static final String LOGTAG = AnimatedVectorDrawable.class.getSimpleName();
+ private static final String LOGTAG = "AnimatedVectorDrawable";
private static final String ANIMATED_VECTOR = "animated-vector";
private static final String TARGET = "target";
private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
+ /**
+ * The resources against which this drawable was created. Used to attempt
+ * to inflate animators if applyTheme() doesn't get called.
+ */
+ private Resources mRes;
+
private AnimatedVectorDrawableState mAnimatedVectorState;
private boolean mMutated;
@@ -144,6 +151,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res) {
mAnimatedVectorState = new AnimatedVectorDrawableState(state, mCallback, res);
+ mRes = res;
}
@Override
@@ -273,6 +281,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
@Override
public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException {
+ final AnimatedVectorDrawableState state = mAnimatedVectorState;
int eventType = parser.getEventType();
float pathErrorScale = 1;
@@ -290,10 +299,10 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
vectorDrawable.setAllowCaching(false);
vectorDrawable.setCallback(mCallback);
pathErrorScale = vectorDrawable.getPixelSize();
- if (mAnimatedVectorState.mVectorDrawable != null) {
- mAnimatedVectorState.mVectorDrawable.setCallback(null);
+ if (state.mVectorDrawable != null) {
+ state.mVectorDrawable.setCallback(null);
}
- mAnimatedVectorState.mVectorDrawable = vectorDrawable;
+ state.mVectorDrawable = vectorDrawable;
}
a.recycle();
} else if (TARGET.equals(tagName)) {
@@ -302,12 +311,25 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
final String target = a.getString(
R.styleable.AnimatedVectorDrawableTarget_name);
- int id = a.getResourceId(
+ final int animResId = a.getResourceId(
R.styleable.AnimatedVectorDrawableTarget_animation, 0);
- if (id != 0) {
- Animator objectAnimator = AnimatorInflater.loadAnimator(res, theme, id,
- pathErrorScale);
- setupAnimatorsForTarget(target, objectAnimator);
+ if (animResId != 0) {
+ if (theme != null) {
+ final Animator objectAnimator = AnimatorInflater.loadAnimator(
+ res, theme, animResId, pathErrorScale);
+ setupAnimatorsForTarget(target, objectAnimator);
+ } else {
+ // The animation may be theme-dependent. As a
+ // workaround until Animator has full support for
+ // applyTheme(), postpone loading the animator
+ // until we have a theme in applyTheme().
+ if (state.mPendingAnims == null) {
+ state.mPendingAnims = new ArrayList<>(1);
+ }
+ state.mPendingAnims.add(
+ new PendingAnimator(animResId, pathErrorScale, target));
+
+ }
}
a.recycle();
}
@@ -315,6 +337,13 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
eventType = parser.next();
}
+
+ // If we don't have any pending animations, we don't need to hold a
+ // reference to the resources.
+ if (state.mPendingAnims == null) {
+ mRes = null;
+ }
+
setupAnimatorSet();
}
@@ -340,6 +369,29 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
if (vectorDrawable != null && vectorDrawable.canApplyTheme()) {
vectorDrawable.applyTheme(t);
}
+
+ if (t != null) {
+ inflatePendingAnimators(t.getResources(), t);
+ }
+ }
+
+ /**
+ * Inflates pending animators, if any, against a theme. Clears the list of
+ * pending animators.
+ *
+ * @param t the theme against which to inflate the animators
+ */
+ private void inflatePendingAnimators(@NonNull Resources res, @Nullable Theme t) {
+ final ArrayList<PendingAnimator> pendingAnims = mAnimatedVectorState.mPendingAnims;
+ if (pendingAnims != null) {
+ mAnimatedVectorState.mPendingAnims = null;
+
+ for (int i = 0, count = pendingAnims.size(); i < count; i++) {
+ final PendingAnimator pendingAnimator = pendingAnims.get(i);
+ final Animator objectAnimator = pendingAnimator.newInstance(res, t);
+ setupAnimatorsForTarget(pendingAnimator.target, objectAnimator);
+ }
+ }
}
/**
@@ -381,6 +433,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
// we add this array into the mAnimatorSet.
private ArrayList<Animator> mTempAnimators;
ArrayMap<Animator, String> mTargetNameMap;
+ ArrayList<PendingAnimator> mPendingAnims;
public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy,
Callback owner, Resources res) {
@@ -403,7 +456,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
final int numAnimators = copy.mTargetNameMap.size();
// Deep copy a animator set, and then setup the target map again.
mAnimatorSet = copy.mAnimatorSet.clone();
- mTargetNameMap = new ArrayMap<Animator, String>(numAnimators);
+ mTargetNameMap = new ArrayMap<>(numAnimators);
// Since the new AnimatorSet is cloned from the old one, the order must be the
// same inside the array.
ArrayList<Animator> oldAnim = copy.mAnimatorSet.getChildAnimations();
@@ -418,6 +471,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
mTargetNameMap.put(newAnim.get(i), targetName);
}
}
+
+ // Shallow copy since the array is immutable after inflate().
+ mPendingAnims = copy.mPendingAnims;
} else {
mVectorDrawable = new VectorDrawable();
}
@@ -426,7 +482,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
@Override
public boolean canApplyTheme() {
return (mVectorDrawable != null && mVectorDrawable.canApplyTheme())
- || super.canApplyTheme();
+ || mPendingAnims != null || super.canApplyTheme();
}
@Override
@@ -445,12 +501,32 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
}
}
+ /**
+ * Basically a constant state for Animators until we actually implement
+ * constant states for Animators.
+ */
+ private static class PendingAnimator {
+ public final int animResId;
+ public final float pathErrorScale;
+ public final String target;
+
+ public PendingAnimator(int animResId, float pathErrorScale, String target) {
+ this.animResId = animResId;
+ this.pathErrorScale = pathErrorScale;
+ this.target = target;
+ }
+
+ public Animator newInstance(Resources res, Theme theme) {
+ return AnimatorInflater.loadAnimator(res, theme, animResId, pathErrorScale);
+ }
+ }
+
private void setupAnimatorsForTarget(String name, Animator animator) {
Object target = mAnimatedVectorState.mVectorDrawable.getTargetByName(name);
animator.setTarget(target);
if (mAnimatedVectorState.mTempAnimators == null) {
- mAnimatedVectorState.mTempAnimators = new ArrayList<Animator>();
- mAnimatedVectorState.mTargetNameMap = new ArrayMap<Animator, String>();
+ mAnimatedVectorState.mTempAnimators = new ArrayList<>();
+ mAnimatedVectorState.mTargetNameMap = new ArrayMap<>();
}
mAnimatedVectorState.mTempAnimators.add(animator);
mAnimatedVectorState.mTargetNameMap.put(animator, name);
@@ -474,6 +550,23 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
if (isStarted()) {
return;
}
+
+ // Check for uninflated animators. We can remove this after we add
+ // support for Animator.applyTheme(). See comments in inflate().
+ if (mAnimatedVectorState.mPendingAnims != null) {
+ // Attempt to load animators without applying a theme.
+ if (mRes != null) {
+ inflatePendingAnimators(mRes, null);
+ mRes = null;
+ } else {
+ Log.e(LOGTAG, "Failed to load animators. Either the AnimatedVectorDrawable must be"
+ + " created using a Resources object or applyTheme() must be called with"
+ + " a non-null Theme object.");
+ }
+
+ mAnimatedVectorState.mPendingAnims = null;
+ }
+
mAnimatedVectorState.mAnimatorSet.start();
invalidateSelf();
}