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

Commit e5e92602 authored by ztenghui's avatar ztenghui
Browse files

Add AnimatedVectorDrawable

Currently as a hidden class.
It can support many the animations now as far as ObjectAnimator and
hierarchical group can support.
And we don't have path morphing yet.

Also support the Animator / Interpolator inflation from Context and Resources.

Change-Id: I948bbdf7373ad291171eed0b497959dce8c2edf3
parent 88b00784
Loading
Loading
Loading
Loading
+137 −100
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@ package android.animation;


import android.content.Context;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.content.res.XmlResourceParser;
import android.content.res.Resources.NotFoundException;
import android.content.res.Resources.NotFoundException;
@@ -25,6 +26,9 @@ import android.util.StateSet;
import android.util.TypedValue;
import android.util.TypedValue;
import android.util.Xml;
import android.util.Xml;
import android.view.animation.AnimationUtils;
import android.view.animation.AnimationUtils;

import com.android.internal.R;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserException;


@@ -66,11 +70,26 @@ public class AnimatorInflater {
     */
     */
    public static Animator loadAnimator(Context context, int id)
    public static Animator loadAnimator(Context context, int id)
            throws NotFoundException {
            throws NotFoundException {
        return loadAnimator(context.getResources(), context.getTheme(), id);
    }

    /**
     * Loads an {@link Animator} object from a resource
     *
     * @param resources The resources
     * @param theme The theme
     * @param id The resource id of the animation to load
     * @return The animator object reference by the specified id
     * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded
     * @hide
     */
    public static Animator loadAnimator(Resources resources, Theme theme, int id)
            throws NotFoundException {


        XmlResourceParser parser = null;
        XmlResourceParser parser = null;
        try {
        try {
            parser = context.getResources().getAnimation(id);
            parser = resources.getAnimation(id);
            return createAnimatorFromXml(context, parser);
            return createAnimatorFromXml(resources, theme, parser);
        } catch (XmlPullParserException ex) {
        } catch (XmlPullParserException ex) {
            Resources.NotFoundException rnf =
            Resources.NotFoundException rnf =
                    new Resources.NotFoundException("Can't load animation resource ID #0x" +
                    new Resources.NotFoundException("Can't load animation resource ID #0x" +
@@ -150,7 +169,8 @@ public class AnimatorInflater {


                        }
                        }
                        if (animator == null) {
                        if (animator == null) {
                            animator = createAnimatorFromXml(context, parser);
                            animator = createAnimatorFromXml(context.getResources(),
                                    context.getTheme(), parser);
                        }
                        }


                        if (animator == null) {
                        if (animator == null) {
@@ -166,103 +186,8 @@ public class AnimatorInflater {
        }
        }
    }
    }


    private static Animator createAnimatorFromXml(Context c, XmlPullParser parser)
            throws XmlPullParserException, IOException {
        return createAnimatorFromXml(c, parser, Xml.asAttributeSet(parser), null, 0);
    }

    private static Animator createAnimatorFromXml(Context c, XmlPullParser parser,
            AttributeSet attrs, AnimatorSet parent, int sequenceOrdering)
            throws XmlPullParserException, IOException {

        Animator anim = null;
        ArrayList<Animator> childAnims = null;

        // Make sure we are on a start tag.
        int type;
        int depth = parser.getDepth();

        while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
               && type != XmlPullParser.END_DOCUMENT) {

            if (type != XmlPullParser.START_TAG) {
                continue;
            }

            String  name = parser.getName();

            if (name.equals("objectAnimator")) {
                anim = loadObjectAnimator(c, attrs);
            } else if (name.equals("animator")) {
                anim = loadAnimator(c, attrs, null);
            } else if (name.equals("set")) {
                anim = new AnimatorSet();
                TypedArray a = c.obtainStyledAttributes(attrs,
                        com.android.internal.R.styleable.AnimatorSet);
                int ordering = a.getInt(com.android.internal.R.styleable.AnimatorSet_ordering,
                        TOGETHER);
                createAnimatorFromXml(c, parser, attrs, (AnimatorSet) anim,  ordering);
                a.recycle();
            } else {
                throw new RuntimeException("Unknown animator name: " + parser.getName());
            }

            if (parent != null) {
                if (childAnims == null) {
                    childAnims = new ArrayList<Animator>();
                }
                childAnims.add(anim);
            }
        }
        if (parent != null && childAnims != null) {
            Animator[] animsArray = new Animator[childAnims.size()];
            int index = 0;
            for (Animator a : childAnims) {
                animsArray[index++] = a;
            }
            if (sequenceOrdering == TOGETHER) {
                parent.playTogether(animsArray);
            } else {
                parent.playSequentially(animsArray);
            }
        }

        return anim;

    }

    private static ObjectAnimator loadObjectAnimator(Context context, AttributeSet attrs)
            throws NotFoundException {

        ObjectAnimator anim = new ObjectAnimator();

        loadAnimator(context, attrs, anim);

        TypedArray a =
                context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.PropertyAnimator);

        String propertyName = a.getString(com.android.internal.R.styleable.PropertyAnimator_propertyName);

        anim.setPropertyName(propertyName);

        a.recycle();

        return anim;
    }

    /**
     * Creates a new animation whose parameters come from the specified context and
     * attributes set.
     *
     * @param context the application environment
     * @param attrs the set of attributes holding the animation parameters
     */
    private static ValueAnimator loadAnimator(Context context, AttributeSet attrs, ValueAnimator anim)
            throws NotFoundException {

        TypedArray a =
                context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animator);


    private static void parseAnimatorFromTypeArray(ValueAnimator anim, TypedArray a) {
        long duration = a.getInt(com.android.internal.R.styleable.Animator_duration, 300);
        long duration = a.getInt(com.android.internal.R.styleable.Animator_duration, 300);


        long startDelay = a.getInt(com.android.internal.R.styleable.Animator_startOffset, 0);
        long startDelay = a.getInt(com.android.internal.R.styleable.Animator_startOffset, 0);
@@ -378,11 +303,123 @@ public class AnimatorInflater {
        if (evaluator != null) {
        if (evaluator != null) {
            anim.setEvaluator(evaluator);
            anim.setEvaluator(evaluator);
        }
        }
    }

    private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser)
            throws XmlPullParserException, IOException {
        return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0);
    }

    private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser,
            AttributeSet attrs, AnimatorSet parent, int sequenceOrdering)
            throws XmlPullParserException, IOException {

        Animator anim = null;
        ArrayList<Animator> childAnims = null;

        // Make sure we are on a start tag.
        int type;
        int depth = parser.getDepth();

        while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
                && type != XmlPullParser.END_DOCUMENT) {

            if (type != XmlPullParser.START_TAG) {
                continue;
            }

            String name = parser.getName();

            if (name.equals("objectAnimator")) {
                anim = loadObjectAnimator(res, theme, attrs);
            } else if (name.equals("animator")) {
                anim = loadAnimator(res, theme, attrs, null);
            } else if (name.equals("set")) {
                anim = new AnimatorSet();
                TypedArray a;
                if (theme != null) {
                    a = theme.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AnimatorSet, 0, 0);
                } else {
                    a = res.obtainAttributes(attrs, com.android.internal.R.styleable.AnimatorSet);
                }
                int ordering = a.getInt(com.android.internal.R.styleable.AnimatorSet_ordering,
                        TOGETHER);
                createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering);
                a.recycle();
            } else {
                throw new RuntimeException("Unknown animator name: " + parser.getName());
            }

            if (parent != null) {
                if (childAnims == null) {
                    childAnims = new ArrayList<Animator>();
                }
                childAnims.add(anim);
            }
        }
        if (parent != null && childAnims != null) {
            Animator[] animsArray = new Animator[childAnims.size()];
            int index = 0;
            for (Animator a : childAnims) {
                animsArray[index++] = a;
            }
            if (sequenceOrdering == TOGETHER) {
                parent.playTogether(animsArray);
            } else {
                parent.playSequentially(animsArray);
            }
        }

        return anim;

    }

    private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs)
            throws NotFoundException {
        ObjectAnimator anim = new ObjectAnimator();

        loadAnimator(res, theme, attrs, anim);

        TypedArray a;
        if (theme != null) {
            a = theme.obtainStyledAttributes(attrs, R.styleable.PropertyAnimator, 0, 0);
        } else {
            a = res.obtainAttributes(attrs, R.styleable.PropertyAnimator);
        }

        String propertyName = a.getString(R.styleable.PropertyAnimator_propertyName);

        anim.setPropertyName(propertyName);

        a.recycle();

        return anim;
    }

    /**
     * Creates a new animation whose parameters come from the specified context
     * and attributes set.
     *
     * @param res The resources
     * @param attrs The set of attributes holding the animation parameters
     */
    private static ValueAnimator loadAnimator(Resources res, Theme theme,
            AttributeSet attrs, ValueAnimator anim)
            throws NotFoundException {

        TypedArray a;
        if (theme != null) {
            a = theme.obtainStyledAttributes(attrs, R.styleable.Animator, 0, 0);
        } else {
            a = res.obtainAttributes(attrs, R.styleable.Animator);
        }

        parseAnimatorFromTypeArray(anim, a);


        final int resID =
        final int resID =
                a.getResourceId(com.android.internal.R.styleable.Animator_interpolator, 0);
                a.getResourceId(com.android.internal.R.styleable.Animator_interpolator, 0);
        if (resID > 0) {
        if (resID > 0) {
            anim.setInterpolator(AnimationUtils.loadInterpolator(context, resID));
            anim.setInterpolator(AnimationUtils.loadInterpolator(res, theme, resID));
        }
        }
        a.recycle();
        a.recycle();


+21 −9
Original line number Original line Diff line number Diff line
@@ -17,9 +17,12 @@
package android.view.animation;
package android.view.animation;


import android.content.Context;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.AttributeSet;


import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
@@ -53,10 +56,19 @@ public class AccelerateInterpolator implements Interpolator, NativeInterpolatorF
    }
    }


    public AccelerateInterpolator(Context context, AttributeSet attrs) {
    public AccelerateInterpolator(Context context, AttributeSet attrs) {
        TypedArray a =
        this(context.getResources(), context.getTheme(), attrs);
            context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AccelerateInterpolator);
    }

    /** @hide */
    public AccelerateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
        TypedArray a;
        if (theme != null) {
            a = theme.obtainStyledAttributes(attrs, R.styleable.AccelerateInterpolator, 0, 0);
        } else {
            a = res.obtainAttributes(attrs, R.styleable.AccelerateInterpolator);
        }


        mFactor = a.getFloat(com.android.internal.R.styleable.AccelerateInterpolator_factor, 1.0f);
        mFactor = a.getFloat(R.styleable.AccelerateInterpolator_factor, 1.0f);
        mDoubleFactor = 2 * mFactor;
        mDoubleFactor = 2 * mFactor;


        a.recycle();
        a.recycle();
+65 −33
Original line number Original line Diff line number Diff line
@@ -20,6 +20,8 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserException;


import android.content.Context;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.XmlResourceParser;
import android.content.res.XmlResourceParser;
import android.content.res.Resources.NotFoundException;
import android.content.res.Resources.NotFoundException;
import android.util.AttributeSet;
import android.util.AttributeSet;
@@ -268,7 +270,7 @@ public class AnimationUtils {
        XmlResourceParser parser = null;
        XmlResourceParser parser = null;
        try {
        try {
            parser = context.getResources().getAnimation(id);
            parser = context.getResources().getAnimation(id);
            return createInterpolatorFromXml(context, parser);
            return createInterpolatorFromXml(context.getResources(), context.getTheme(), parser);
        } catch (XmlPullParserException ex) {
        } catch (XmlPullParserException ex) {
            NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
            NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
                    Integer.toHexString(id));
                    Integer.toHexString(id));
@@ -285,7 +287,38 @@ public class AnimationUtils {


    }
    }


    private static Interpolator createInterpolatorFromXml(Context c, XmlPullParser parser)
    /**
     * Loads an {@link Interpolator} object from a resource
     *
     * @param res The resources
     * @param id The resource id of the animation to load
     * @return The interpolator object reference by the specified id
     * @throws NotFoundException
     * @hide
     */
    public static Interpolator loadInterpolator(Resources res, Theme theme, int id) throws NotFoundException {
        XmlResourceParser parser = null;
        try {
            parser = res.getAnimation(id);
            return createInterpolatorFromXml(res, theme, parser);
        } catch (XmlPullParserException ex) {
            NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
                    Integer.toHexString(id));
            rnf.initCause(ex);
            throw rnf;
        } catch (IOException ex) {
            NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
                    Integer.toHexString(id));
            rnf.initCause(ex);
            throw rnf;
        } finally {
            if (parser != null)
                parser.close();
        }

    }

    private static Interpolator createInterpolatorFromXml(Resources res, Theme theme, XmlPullParser parser)
            throws XmlPullParserException, IOException {
            throws XmlPullParserException, IOException {


        Interpolator interpolator = null;
        Interpolator interpolator = null;
@@ -305,27 +338,26 @@ public class AnimationUtils {


            String name = parser.getName();
            String name = parser.getName();


            
            if (name.equals("linearInterpolator")) {
            if (name.equals("linearInterpolator")) {
                interpolator = new LinearInterpolator(c, attrs);
                interpolator = new LinearInterpolator();
            } else if (name.equals("accelerateInterpolator")) {
            } else if (name.equals("accelerateInterpolator")) {
                interpolator = new AccelerateInterpolator(c, attrs);
                interpolator = new AccelerateInterpolator(res, theme, attrs);
            } else if (name.equals("decelerateInterpolator")) {
            } else if (name.equals("decelerateInterpolator")) {
                interpolator = new DecelerateInterpolator(c, attrs);
                interpolator = new DecelerateInterpolator(res, theme, attrs);
            } else if (name.equals("accelerateDecelerateInterpolator")) {
            } else if (name.equals("accelerateDecelerateInterpolator")) {
                interpolator = new AccelerateDecelerateInterpolator(c, attrs);
                interpolator = new AccelerateDecelerateInterpolator();
            } else if (name.equals("cycleInterpolator")) {
            } else if (name.equals("cycleInterpolator")) {
                interpolator = new CycleInterpolator(c, attrs);
                interpolator = new CycleInterpolator(res, theme, attrs);
            } else if (name.equals("anticipateInterpolator")) {
            } else if (name.equals("anticipateInterpolator")) {
                interpolator = new AnticipateInterpolator(c, attrs);
                interpolator = new AnticipateInterpolator(res, theme, attrs);
            } else if (name.equals("overshootInterpolator")) {
            } else if (name.equals("overshootInterpolator")) {
                interpolator = new OvershootInterpolator(c, attrs);
                interpolator = new OvershootInterpolator(res, theme, attrs);
            } else if (name.equals("anticipateOvershootInterpolator")) {
            } else if (name.equals("anticipateOvershootInterpolator")) {
                interpolator = new AnticipateOvershootInterpolator(c, attrs);
                interpolator = new AnticipateOvershootInterpolator(res, theme, attrs);
            } else if (name.equals("bounceInterpolator")) {
            } else if (name.equals("bounceInterpolator")) {
                interpolator = new BounceInterpolator(c, attrs);
                interpolator = new BounceInterpolator();
            } else if (name.equals("pathInterpolator")) {
            } else if (name.equals("pathInterpolator")) {
                interpolator = new PathInterpolator(c, attrs);
                interpolator = new PathInterpolator(res, theme, attrs);
            } else {
            } else {
                throw new RuntimeException("Unknown interpolator name: " + parser.getName());
                throw new RuntimeException("Unknown interpolator name: " + parser.getName());
            }
            }
+15 −3
Original line number Original line Diff line number Diff line
@@ -17,9 +17,12 @@
package android.view.animation;
package android.view.animation;


import android.content.Context;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
import android.util.AttributeSet;
import android.util.AttributeSet;


import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
@@ -45,11 +48,20 @@ public class AnticipateInterpolator implements Interpolator, NativeInterpolatorF
    }
    }


    public AnticipateInterpolator(Context context, AttributeSet attrs) {
    public AnticipateInterpolator(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs,
        this(context.getResources(), context.getTheme(), attrs);
                com.android.internal.R.styleable.AnticipateInterpolator);
    }

    /** @hide */
    public AnticipateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
        TypedArray a;
        if (theme != null) {
            a = theme.obtainStyledAttributes(attrs, R.styleable.AnticipateInterpolator, 0, 0);
        } else {
            a = res.obtainAttributes(attrs, R.styleable.AnticipateInterpolator);
        }


        mTension =
        mTension =
                a.getFloat(com.android.internal.R.styleable.AnticipateInterpolator_tension, 2.0f);
                a.getFloat(R.styleable.AnticipateInterpolator_tension, 2.0f);


        a.recycle();
        a.recycle();
    }
    }
+13 −1
Original line number Original line Diff line number Diff line
@@ -17,6 +17,8 @@
package android.view.animation;
package android.view.animation;


import android.content.Context;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.AttributeSet;


@@ -62,7 +64,17 @@ public class AnticipateOvershootInterpolator implements Interpolator, NativeInte
    }
    }


    public AnticipateOvershootInterpolator(Context context, AttributeSet attrs) {
    public AnticipateOvershootInterpolator(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs, AnticipateOvershootInterpolator);
        this(context.getResources(), context.getTheme(), attrs);
    }

    /** @hide */
    public AnticipateOvershootInterpolator(Resources res, Theme theme, AttributeSet attrs) {
        TypedArray a;
        if (theme != null) {
            a = theme.obtainStyledAttributes(attrs, AnticipateOvershootInterpolator, 0, 0);
        } else {
            a = res.obtainAttributes(attrs, AnticipateOvershootInterpolator);
        }


        mTension = a.getFloat(AnticipateOvershootInterpolator_tension, 2.0f) *
        mTension = a.getFloat(AnticipateOvershootInterpolator_tension, 2.0f) *
                a.getFloat(AnticipateOvershootInterpolator_extraTension, 1.5f);
                a.getFloat(AnticipateOvershootInterpolator_extraTension, 1.5f);
Loading