Project: cow
/*
 * Copyright (C) 2010 The Android Open Source Project 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
 
package com.actionbarsherlock.internal.nineoldandroids.animation; 
 
import android.animation.TimeInterpolator; 
import android.view.animation.Interpolator; 
 
/**
 * This class holds a time/value pair for an animation. The Keyframe class is used 
 * by {@link ValueAnimator} to define the values that the animation target will have over the course 
 * of the animation. As the time proceeds from one keyframe to the other, the value of the 
 * target object will animate between the value at the previous keyframe and the value at the 
 * next keyframe. Each keyframe also holds an optional {@link TimeInterpolator} 
 * object, which defines the time interpolation over the intervalue preceding the keyframe. 
 * 
 * <p>The Keyframe class itself is abstract. The type-specific factory methods will return 
 * a subclass of Keyframe specific to the type of value being stored. This is done to improve 
 * performance when dealing with the most common cases (e.g., <code>float</code> and 
 * <code>int</code> values). Other types will fall into a more general Keyframe class that 
 * treats its values as Objects. Unless your animation requires dealing with a custom type 
 * or a data structure that needs to be animated directly (and evaluated using an implementation 
 * of {@link TypeEvaluator}), you should stick to using float and int as animations using those 
 * types have lower runtime overhead than other types.</p> 
 */
 
public abstract class Keyframe implements Cloneable { 
    /**
     * The time at which mValue will hold true. 
     */
 
    float mFraction; 
 
    /**
     * The type of the value in this Keyframe. This type is determined at construction time, 
     * based on the type of the <code>value</code> object passed into the constructor. 
     */
 
    Class mValueType; 
 
    /**
     * The optional time interpolator for the interval preceding this keyframe. A null interpolator 
     * (the default) results in linear interpolation over the interval. 
     */
 
    private /*Time*/Interpolator mInterpolator = null
 
    /**
     * Flag to indicate whether this keyframe has a valid value. This flag is used when an 
     * animation first starts, to populate placeholder keyframes with real values derived 
     * from the target object. 
     */
 
    boolean mHasValue = false
 
    /**
     * Constructs a Keyframe object with the given time and value. The time defines the 
     * time, as a proportion of an overall animation's duration, at which the value will hold true 
     * for the animation. The value for the animation between keyframes will be calculated as 
     * an interpolation between the values at those keyframes. 
     * 
     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction 
     * of time elapsed of the overall animation duration. 
     * @param value The value that the object will animate to as the animation time approaches 
     * the time in this keyframe, and the the value animated from as the time passes the time in 
     * this keyframe. 
     */
 
    public static Keyframe ofInt(float fraction, int value) { 
        return new IntKeyframe(fraction, value); 
    } 
 
    /**
     * Constructs a Keyframe object with the given time. The value at this time will be derived 
     * from the target object when the animation first starts (note that this implies that keyframes 
     * with no initial value must be used as part of an {@link ObjectAnimator}). 
     * The time defines the 
     * time, as a proportion of an overall animation's duration, at which the value will hold true 
     * for the animation. The value for the animation between keyframes will be calculated as 
     * an interpolation between the values at those keyframes. 
     * 
     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction 
     * of time elapsed of the overall animation duration. 
     */
 
    public static Keyframe ofInt(float fraction) { 
        return new IntKeyframe(fraction); 
    } 
 
    /**
     * Constructs a Keyframe object with the given time and value. The time defines the 
     * time, as a proportion of an overall animation's duration, at which the value will hold true 
     * for the animation. The value for the animation between keyframes will be calculated as 
     * an interpolation between the values at those keyframes. 
     * 
     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction 
     * of time elapsed of the overall animation duration. 
     * @param value The value that the object will animate to as the animation time approaches 
     * the time in this keyframe, and the the value animated from as the time passes the time in 
     * this keyframe. 
     */
 
    public static Keyframe ofFloat(float fraction, float value) { 
        return new FloatKeyframe(fraction, value); 
    } 
 
    /**
     * Constructs a Keyframe object with the given time. The value at this time will be derived 
     * from the target object when the animation first starts (note that this implies that keyframes 
     * with no initial value must be used as part of an {@link ObjectAnimator}). 
     * The time defines the 
     * time, as a proportion of an overall animation's duration, at which the value will hold true 
     * for the animation. The value for the animation between keyframes will be calculated as 
     * an interpolation between the values at those keyframes. 
     * 
     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction 
     * of time elapsed of the overall animation duration. 
     */
 
    public static Keyframe ofFloat(float fraction) { 
        return new FloatKeyframe(fraction); 
    } 
 
    /**
     * Constructs a Keyframe object with the given time and value. The time defines the 
     * time, as a proportion of an overall animation's duration, at which the value will hold true 
     * for the animation. The value for the animation between keyframes will be calculated as 
     * an interpolation between the values at those keyframes. 
     * 
     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction 
     * of time elapsed of the overall animation duration. 
     * @param value The value that the object will animate to as the animation time approaches 
     * the time in this keyframe, and the the value animated from as the time passes the time in 
     * this keyframe. 
     */
 
    public static Keyframe ofObject(float fraction, Object value) { 
        return new ObjectKeyframe(fraction, value); 
    } 
 
    /**
     * Constructs a Keyframe object with the given time. The value at this time will be derived 
     * from the target object when the animation first starts (note that this implies that keyframes 
     * with no initial value must be used as part of an {@link ObjectAnimator}). 
     * The time defines the 
     * time, as a proportion of an overall animation's duration, at which the value will hold true 
     * for the animation. The value for the animation between keyframes will be calculated as 
     * an interpolation between the values at those keyframes. 
     * 
     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction 
     * of time elapsed of the overall animation duration. 
     */
 
    public static Keyframe ofObject(float fraction) { 
        return new ObjectKeyframe(fraction, null); 
    } 
 
    /**
     * Indicates whether this keyframe has a valid value. This method is called internally when 
     * an {@link ObjectAnimator} first starts; keyframes without values are assigned values at 
     * that time by deriving the value for the property from the target object. 
     * 
     * @return boolean Whether this object has a value assigned. 
     */
 
    public boolean hasValue() { 
        return mHasValue; 
    } 
 
    /**
     * Gets the value for this Keyframe. 
     * 
     * @return The value for this Keyframe. 
     */
 
    public abstract Object getValue(); 
 
    /**
     * Sets the value for this Keyframe. 
     * 
     * @param value value for this Keyframe. 
     */
 
    public abstract void setValue(Object value); 
 
    /**
     * Gets the time for this keyframe, as a fraction of the overall animation duration. 
     * 
     * @return The time associated with this keyframe, as a fraction of the overall animation 
     * duration. This should be a value between 0 and 1. 
     */
 
    public float getFraction() { 
        return mFraction; 
    } 
 
    /**
     * Sets the time for this keyframe, as a fraction of the overall animation duration. 
     * 
     * @param fraction time associated with this keyframe, as a fraction of the overall animation 
     * duration. This should be a value between 0 and 1. 
     */
 
    public void setFraction(float fraction) { 
        mFraction = fraction; 
    } 
 
    /**
     * Gets the optional interpolator for this Keyframe. A value of <code>null</code> indicates 
     * that there is no interpolation, which is the same as linear interpolation. 
     * 
     * @return The optional interpolator for this Keyframe. 
     */
 
    public /*Time*/Interpolator getInterpolator() { 
        return mInterpolator; 
    } 
 
    /**
     * Sets the optional interpolator for this Keyframe. A value of <code>null</code> indicates 
     * that there is no interpolation, which is the same as linear interpolation. 
     * 
     * @return The optional interpolator for this Keyframe. 
     */
 
    public void setInterpolator(/*Time*/Interpolator interpolator) { 
        mInterpolator = interpolator; 
    } 
 
    /**
     * Gets the type of keyframe. This information is used by ValueAnimator to determine the type of 
     * {@link TypeEvaluator} to use when calculating values between keyframes. The type is based 
     * on the type of Keyframe created. 
     * 
     * @return The type of the value stored in the Keyframe. 
     */
 
    public Class getType() { 
        return mValueType; 
    } 
 
    @Override 
    public abstract Keyframe clone(); 
 
    /**
     * This internal subclass is used for all types which are not int or float. 
     */
 
    static class ObjectKeyframe extends Keyframe { 
 
        /**
         * The value of the animation at the time mFraction. 
         */
 
        Object mValue; 
 
        ObjectKeyframe(float fraction, Object value) { 
            mFraction = fraction; 
            mValue = value; 
            mHasValue = (value != null); 
            mValueType = mHasValue ? value.getClass() : Object.class
        } 
 
        public Object getValue() { 
            return mValue; 
        } 
 
        public void setValue(Object value) { 
            mValue = value; 
            mHasValue = (value != null); 
        } 
 
        @Override 
        public ObjectKeyframe clone() { 
            ObjectKeyframe kfClone = new ObjectKeyframe(getFraction(), mValue); 
            kfClone.setInterpolator(getInterpolator()); 
            return kfClone; 
        } 
    } 
 
    /**
     * Internal subclass used when the keyframe value is of type int. 
     */
 
    static class IntKeyframe extends Keyframe { 
 
        /**
         * The value of the animation at the time mFraction. 
         */
 
        int mValue; 
 
        IntKeyframe(float fraction, int value) { 
            mFraction = fraction; 
            mValue = value; 
            mValueType = int.class
            mHasValue = true
        } 
 
        IntKeyframe(float fraction) { 
            mFraction = fraction; 
            mValueType = int.class
        } 
 
        public int getIntValue() { 
            return mValue; 
        } 
 
        public Object getValue() { 
            return mValue; 
        } 
 
        public void setValue(Object value) { 
            if (value != null && value.getClass() == Integer.class) { 
                mValue = ((Integer)value).intValue(); 
                mHasValue = true
            } 
        } 
 
        @Override 
        public IntKeyframe clone() { 
            IntKeyframe kfClone = new IntKeyframe(getFraction(), mValue); 
            kfClone.setInterpolator(getInterpolator()); 
            return kfClone; 
        } 
    } 
 
    /**
     * Internal subclass used when the keyframe value is of type float. 
     */
 
    static class FloatKeyframe extends Keyframe { 
        /**
         * The value of the animation at the time mFraction. 
         */
 
        float mValue; 
 
        FloatKeyframe(float fraction, float value) { 
            mFraction = fraction; 
            mValue = value; 
            mValueType = float.class
            mHasValue = true
        } 
 
        FloatKeyframe(float fraction) { 
            mFraction = fraction; 
            mValueType = float.class
        } 
 
        public float getFloatValue() { 
            return mValue; 
        } 
 
        public Object getValue() { 
            return mValue; 
        } 
 
        public void setValue(Object value) { 
            if (value != null && value.getClass() == Float.class) { 
                mValue = ((Float)value).floatValue(); 
                mHasValue = true
            } 
        } 
 
        @Override 
        public FloatKeyframe clone() { 
            FloatKeyframe kfClone = new FloatKeyframe(getFraction(), mValue); 
            kfClone.setInterpolator(getInterpolator()); 
            return kfClone; 
        } 
    } 
}