Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6f6578e8 authored by Chet Haase's avatar Chet Haase
Browse files

Use constant state in AnimatedVectorDrawable

Complex animated vector drawables can be expensive to load due to
sub-optimal parsing of the String-based pathData. Suffering that penalty
every time the same drawable is loaded (such as material-themed
ProgressBars) is painful.

The new approach caches constant state of both the VectorDrawable (including
the pathData geometry) and the animators (which includes potentially expensive
path-based interpolators).

issue #17366831 Material ProgressBar taking 200+ms to inflate

Change-Id: Iba3b541e24cfce8c07f5aa9fe6aa7d7b92b2fe1c
parent 9da6c905
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -636,6 +636,7 @@ public final class AnimatorSet extends Animator {
        anim.mNodes = new ArrayList<Node>();
        anim.mSortedNodes = new ArrayList<Node>();
        anim.mReversible = mReversible;
        anim.mSetListener = null;

        // Walk through the old nodes list, cloning each node and adding it to the new nodemap.
        // One problem is that the old node dependencies point to nodes in the old AnimatorSet.
+40 −7
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.graphics.ColorFilter;
import android.graphics.Outline;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;

@@ -131,7 +132,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {

    private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;

    private final AnimatedVectorDrawableState mAnimatedVectorState;
    private AnimatedVectorDrawableState mAnimatedVectorState;

    private boolean mMutated;

    public AnimatedVectorDrawable() {
        mAnimatedVectorState = new AnimatedVectorDrawableState(
@@ -140,16 +143,24 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {

    private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res,
            Theme theme) {
        // TODO: Correctly handle the constant state for AVD.
        mAnimatedVectorState = new AnimatedVectorDrawableState(state);
        if (theme != null && canApplyTheme()) {
            applyTheme(theme);
        }
    }

    @Override
    public Drawable mutate() {
        if (!mMutated && super.mutate() == this) {
            mAnimatedVectorState = new AnimatedVectorDrawableState(mAnimatedVectorState);
            mMutated = true;
        }
        return this;
    }

    @Override
    public ConstantState getConstantState() {
        return null;
        return mAnimatedVectorState;
    }

    @Override
@@ -311,14 +322,31 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
        int mChangingConfigurations;
        VectorDrawable mVectorDrawable;
        ArrayList<Animator> mAnimators;
        ArrayMap<Animator, String> mTargetNameMap;

        public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy) {
            if (copy != null) {
                mChangingConfigurations = copy.mChangingConfigurations;
                // TODO: Make sure the constant state are handled correctly.
                mVectorDrawable = new VectorDrawable();
                if (copy.mVectorDrawable != null) {
                    mVectorDrawable = (VectorDrawable) copy.mVectorDrawable.getConstantState().newDrawable();
                    mVectorDrawable.mutate();
                    mVectorDrawable.setAllowCaching(false);
                mAnimators = new ArrayList<Animator>();
                    mVectorDrawable.setBounds(copy.mVectorDrawable.getBounds());
                }
                if (copy.mAnimators != null) {
                    final int numAnimators = copy.mAnimators.size();
                    mAnimators = new ArrayList<Animator>(numAnimators);
                    mTargetNameMap = new ArrayMap<Animator, String>(numAnimators);
                    for (int i = 0; i < numAnimators; ++i) {
                        Animator anim = copy.mAnimators.get(i);
                        Animator animClone = anim.clone();
                        String targetName = copy.mTargetNameMap.get(anim);
                        Object targetObject = mVectorDrawable.getTargetByName(targetName);
                        animClone.setTarget(targetObject);
                        mAnimators.add(animClone);
                        mTargetNameMap.put(animClone, targetName);
                    }
                }
            }
        }

@@ -346,7 +374,12 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
    private void setupAnimatorsForTarget(String name, Animator animator) {
        Object target = mAnimatedVectorState.mVectorDrawable.getTargetByName(name);
        animator.setTarget(target);
        if (mAnimatedVectorState.mAnimators == null) {
            mAnimatedVectorState.mAnimators = new ArrayList<Animator>();
            mAnimatedVectorState.mTargetNameMap = new ArrayMap<Animator, String>();
        }
        mAnimatedVectorState.mAnimators.add(animator);
        mAnimatedVectorState.mTargetNameMap.put(animator, name);
        if (DBG_ANIMATION_VECTOR_DRAWABLE) {
            Log.v(LOGTAG, "add animator  for target " + name + " " + animator);
        }
+15 −2
Original line number Diff line number Diff line
@@ -629,6 +629,15 @@ public class VectorDrawable extends Drawable {
                mThemeAttrs = copy.mThemeAttrs;
                mChangingConfigurations = copy.mChangingConfigurations;
                mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
                if (copy.mVPathRenderer.mFillPaint != null) {
                    mVPathRenderer.mFillPaint = new Paint(copy.mVPathRenderer.mFillPaint);
                }
                if (copy.mVPathRenderer.mStrokePaint != null) {
                    mVPathRenderer.mStrokePaint = new Paint(copy.mVPathRenderer.mStrokePaint);
                }
                if (copy.mVPathRenderer.mColorFilter != null) {
                    mVPathRenderer.mColorFilter = copy.mVPathRenderer.mColorFilter;
                }
                mTint = copy.mTint;
                mTintMode = copy.mTintMode;
                mAutoMirrored = copy.mAutoMirrored;
@@ -700,8 +709,8 @@ public class VectorDrawable extends Drawable {
         */
        // Variables that only used temporarily inside the draw() call, so there
        // is no need for deep copying.
        private final Path mPath = new Path();
        private final Path mRenderPath = new Path();
        private final Path mPath;
        private final Path mRenderPath;
        private static final Matrix IDENTITY_MATRIX = new Matrix();
        private final Matrix mFinalPathMatrix = new Matrix();

@@ -724,6 +733,8 @@ public class VectorDrawable extends Drawable {

        public VPathRenderer() {
            mRootGroup = new VGroup();
            mPath = new Path();
            mRenderPath = new Path();
        }

        public void setRootAlpha(int alpha) {
@@ -736,6 +747,8 @@ public class VectorDrawable extends Drawable {

        public VPathRenderer(VPathRenderer copy) {
            mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
            mPath = new Path(copy.mPath);
            mRenderPath = new Path(copy.mRenderPath);
            mBaseWidth = copy.mBaseWidth;
            mBaseHeight = copy.mBaseHeight;
            mViewportWidth = copy.mViewportWidth;