public class AlphaAnimation extends AnimationBase<AlphaAnimation>{
	
	/** The gradient change of attribute values */
	protected float[] values;

	/*
	 * ==================================================================
	 * Constructor
	 * ==================================================================
	 */
	
	public AlphaAnimation(View targetView) {
		this.targetView = targetView;
		interpolator = new AccelerateDecelerateInterpolator();
		duration = Duration.DURATION_LONG;
		listener = null;
		
		values = new float[]{ 1.0f };
	}
	
	/*
	 * ==================================================================
	 * Override CombinableMethod
	 * ==================================================================
	 */

	@Override
	public void animate() {
		createAnimatorSet().start();
	}

	@Override
	public AnimatorSet createAnimatorSet() {
		targetView.setAlpha(0f);
		targetView.setVisibility(View.VISIBLE);

		AnimatorSet fadeSet = new AnimatorSet();
		fadeSet.play(ObjectAnimator.ofFloat(targetView, View.ALPHA, values));
		fadeSet.setInterpolator(interpolator);
		fadeSet.setDuration(duration);
		if (listener != null) {
			fadeSet.addListener(listener);
		}
	
		return fadeSet;
	}
	
	
	/*
	 * ==================================================================
	 * Getter And Setter
	 * ==================================================================
	 */

	public AlphaAnimation setValues(float[] values) {
		this.values = values;
		
		return this;
	}

} public class BlindAnimation extends AnimationBase<BlindAnimation>{
	
	private int direction = Direction.DIRECTION_UP;
	int blindMode = BlindMode.IN;
	
	public interface BlindMode {
		public static final int IN = 0x01, OUT = 0x02;
	}

	/*
	 * ==================================================================
	 * Constructor
	 * ==================================================================
	 */

	public BlindAnimation(View targetView) {
		this.targetView = targetView;
		interpolator = new AccelerateDecelerateInterpolator();
		duration = Duration.DURATION_LONG;
		listener = null;
	}

	/*
	 * ==================================================================
	 * Override CombinableMethod
	 * ==================================================================
	 */

	@Override
	public void animate() {

		createAnimatorSet().start();

	}

	@Override
	public AnimatorSet createAnimatorSet() {
		final ViewGroup parent = (ViewGroup) targetView.getParent(),
				animationLayout = new FrameLayout(targetView.getContext());
		final int positionView = parent.indexOfChild(targetView);
		animationLayout.setLayoutParams(targetView.getLayoutParams());
		parent.removeView(targetView);
		animationLayout.addView(targetView);
		parent.addView(animationLayout, positionView);
		
		final float originalScaleY = targetView.getScaleY();
		ObjectAnimator scaleY  = null , scaleY_child= null;
		
		switch (blindMode) {
		case BlindMode.IN:
			switch (direction) {
			case Direction.DIRECTION_UP:
				
				scaleY = ObjectAnimator.ofFloat(animationLayout, View.SCALE_Y, 0f , 1.0f);
				scaleY_child = ObjectAnimator.ofFloat(targetView, View.SCALE_Y, 2.5f , 1.0f);

				animationLayout.setPivotX(0);
				animationLayout.setPivotY(0);
				targetView.setPivotX(0);
				targetView.setPivotY(0);
				
				break;

			case Direction.DIRECTION_DOWN:
				
				scaleY = ObjectAnimator.ofFloat(animationLayout, View.SCALE_Y, 0f , 1.0f);
				scaleY_child = ObjectAnimator.ofFloat(targetView, View.SCALE_Y, 2.5f , 1.0f);

				animationLayout.setPivotX(0);
				animationLayout.setPivotY(targetView.getHeight());
				targetView.setPivotX(0);
				targetView.setPivotY(targetView.getHeight());
				break;
			case Direction.DIRECTION_LEFT:
				
				scaleY = ObjectAnimator.ofFloat(animationLayout, View.SCALE_X, 0f , 1.0f);
				scaleY_child = ObjectAnimator.ofFloat(targetView, View.SCALE_X, 2.5f , 1.0f);

				animationLayout.setPivotX(0);
				animationLayout.setPivotY(targetView.getHeight());
				targetView.setPivotX(0);
				targetView.setPivotY(targetView.getHeight());
				break;
			case Direction.DIRECTION_RIGHT:
				
				scaleY = ObjectAnimator.ofFloat(animationLayout, View.SCALE_X, 0f , 1.0f);
				scaleY_child = ObjectAnimator.ofFloat(targetView, View.SCALE_X, 2.5f , 1.0f);

				animationLayout.setPivotX(targetView.getWidth());
				animationLayout.setPivotY(0);
				targetView.setPivotX(targetView.getWidth());
				targetView.setPivotY(0);
				break;
			}
			break;

		case BlindMode.OUT:
			switch (direction) {
			case Direction.DIRECTION_UP:
				
				scaleY = ObjectAnimator.ofFloat(animationLayout, View.SCALE_Y, 0f);
				scaleY_child = ObjectAnimator.ofFloat(targetView, View.SCALE_Y, 2.5f);

				animationLayout.setPivotX(0);
				animationLayout.setPivotY(targetView.getHeight());
				targetView.setPivotX(0);
				targetView.setPivotY(targetView.getHeight());
				break;

			case Direction.DIRECTION_DOWN:
				
				scaleY = ObjectAnimator.ofFloat(animationLayout, View.SCALE_Y, 0f);
				scaleY_child = ObjectAnimator.ofFloat(targetView, View.SCALE_Y, 2.5f);

				animationLayout.setPivotX(0);
				animationLayout.setPivotY(0);
				targetView.setPivotX(0);
				targetView.setPivotY(0);
				break;
			case Direction.DIRECTION_LEFT:
				
				scaleY = ObjectAnimator.ofFloat(animationLayout, View.SCALE_X, 0f);
				scaleY_child = ObjectAnimator.ofFloat(targetView, View.SCALE_X, 2.5f);

				animationLayout.setPivotX(targetView.getWidth());
				animationLayout.setPivotY(0);
				targetView.setPivotX(targetView.getWidth());
				targetView.setPivotY(0);
			
				break;
			case Direction.DIRECTION_RIGHT:
				
				scaleY = ObjectAnimator.ofFloat(animationLayout, View.SCALE_X, 0f);
				scaleY_child = ObjectAnimator.ofFloat(targetView, View.SCALE_X, 2.5f);

				animationLayout.setPivotX(0);
				animationLayout.setPivotY(targetView.getHeight());
				targetView.setPivotX(0);
				targetView.setPivotY(targetView.getHeight());
				break;
			}
			break;
		}

		AnimatorSet blindAnimationSet = new AnimatorSet();
		blindAnimationSet.playTogether(scaleY, scaleY_child);
		blindAnimationSet.setInterpolator(interpolator);
		blindAnimationSet.setDuration(duration / 2);
		blindAnimationSet.addListener(new AnimatorListenerAdapter() {
			@Override
			public void onAnimationStart(Animator animation) {
				switch (blindMode) {
				case BlindMode.IN:
					targetView.setVisibility(View.VISIBLE);
					break;

				case BlindMode.OUT:
					break;
				}
				if (listener != null) {
					listener.onAnimationStart(animation);
				}
			}

			@Override
			public void onAnimationEnd(Animator animation) {
				switch (blindMode) {
				case BlindMode.IN:
					
					break;

				case BlindMode.OUT:
					targetView.setVisibility(View.INVISIBLE);
					break;
				}
				targetView.setScaleY(originalScaleY);
				animationLayout.removeAllViews();
				parent.removeView(animationLayout);
				parent.addView(targetView, positionView);
				
				if (listener != null) {
					listener.onAnimationEnd(animation);
				}
			}

			@Override
			public void onAnimationCancel(Animator animation) {
				if (listener != null) {
					listener.onAnimationCancel(animation);
				}
			}

			@Override
			public void onAnimationRepeat(Animator animation) {
				if (listener != null) {
					listener.onAnimationRepeat(animation);
				}
			}

		});
		return blindAnimationSet;
	}


	
	/*
	 * ==================================================================
	 * Getter And Setter
	 * ==================================================================
	 */
	
	public int getDirection() {
		return direction;
	}

	public BlindAnimation setDirection(int direction) {
		this.direction = direction;
		
		return this;
	}

	public int getBlindMode() {
		return blindMode;
	}

	public BlindAnimation setBlindMode(int blindMode) {
		this.blindMode = blindMode;
		
		return this;
	}

} public class ColorAnimation extends AnimationBase<ColorAnimation>{
	
	private int[] values;
	private String propertiesName;
	
	/*
	 * ==================================================================
	 * Constructor
	 * ==================================================================
	 */
	
	public ColorAnimation(View targetView) {
		this.targetView = targetView;
		interpolator = new LinearInterpolator();
		duration = Duration.DURATION_LONG;
		listener = null;
		
		values = new int[]{ Color.BLACK,Color.WHITE };
		propertiesName = "backgroundColor";
	}
	
	/*
	 * ==================================================================
	 * Override CombinableMethod
	 * ==================================================================
	 */

	@Override
	public void animate() {
		createAnimatorSet().start();
	}
	@Override
	public AnimatorSet createAnimatorSet() {
		ValueAnimator colorAnim = ObjectAnimator.ofInt(targetView, propertiesName, values);
        colorAnim.setDuration(3000);
        colorAnim.setEvaluator(new ArgbEvaluator());
        AnimatorSet colorSet = new AnimatorSet();
        colorSet.play(colorAnim);
        if (listener != null) {
			colorSet.addListener(listener);
		}
		return colorSet;
	}


	
	/*
	 * ==================================================================
	 * Getter And Setter
	 * ==================================================================
	 */

	public int[] getValues() {
		return values;
	}

	public ColorAnimation setValues(int[] values) {
		this.values = values;
		
		return this;
	}

	public String getPropertiesName() {
		return propertiesName;
	}

	public ColorAnimation setPropertiesName(String propertiesName) {
		this.propertiesName = propertiesName;
		
		return this;
	}
	
	
	

} public class CombinationAnimation extends AnimationBase<CombinationAnimation>{

	ArrayList<CombinableMethod<?>> combinableList;

	/*
	 * ==================================================================
	 * Constructor
	 * ==================================================================
	 */
	
	public CombinationAnimation() {
		interpolator = null;
		duration = 0;
		combinableList = new ArrayList<CombinableMethod<?>>();
		listener = null;
	}

	public CombinationAnimation add(CombinableMethod<?> combinable) {
		combinableList.add(combinable);
		return this;
	}
	
	/*
	 * ==================================================================
	 * Override CombinableMethod
	 * ==================================================================
	 */

	@Override
	public void animate() {

		createAnimatorSet().start();
	}
	

	@Override
	public AnimatorSet createAnimatorSet() {
		ArrayList<Animator> animatorList = new ArrayList<Animator>();
		for (int i = 0; i < combinableList.size(); i++) {
			if (duration > 0) {
				combinableList.get(i).setDuration(duration);
			}
			animatorList.add(combinableList.get(i).createAnimatorSet());
		}

		AnimatorSet parallelSet = new AnimatorSet();
		parallelSet.playTogether(animatorList);

		if (interpolator != null) {
			parallelSet.setInterpolator(interpolator);
		}

		parallelSet.addListener(new AnimatorListenerAdapter() {

			@Override
			public void onAnimationEnd(Animator animation) {
				if (listener != null) {
					listener.onAnimationEnd(animation);
				}
			}
		});
		return parallelSet;
	}


} public class FlipAnimation extends AnimationBase<FlipAnimation>{

	public static final int PIVOT_CENTER = 0, PIVOT_LEFT = 1, PIVOT_RIGHT = 2,
			 PIVOT_TOP = 3, PIVOT_BOTTOM = 4;

	float degrees;
	int pivot;
	int orientation = Orientation.HORIZONTAL;
	
	/*
	 * ==================================================================
	 * Constructor
	 * ==================================================================
	 */
	
	public FlipAnimation(View targetView) {
		this.targetView = targetView;
		degrees = 360;
		pivot = PIVOT_CENTER;
		interpolator = new AccelerateDecelerateInterpolator();
		duration = Duration.DURATION_LONG;
		listener = null;
	}

	/*
	 * ==================================================================
	 * Override CombinableMethod
	 * ==================================================================
	 */
	
	@Override
	public void animate() {
		createAnimatorSet().start();
	}

	@Override
	public AnimatorSet createAnimatorSet() {
		ViewHelper.setClipChildren(targetView, false);

		AnimatorSet flipSet = new AnimatorSet();
		switch (orientation) {
		case Orientation.HORIZONTAL:
			flipSet.play(ObjectAnimator.ofFloat(targetView, View.ROTATION_Y,
					targetView.getRotationY() + degrees));
			break;

	    case Orientation.VERTICAL:
	    	flipSet.play(ObjectAnimator.ofFloat(targetView, View.ROTATION_X,
	    			targetView.getRotationX() + degrees));
			break;
		}
		
		flipSet.setInterpolator(interpolator);
		flipSet.setDuration(duration);
		if (listener != null ) {
			flipSet.addListener(listener);
		}
		return flipSet;
	}
	
	/*
	 * ==================================================================
	 * Getter And Setter
	 * ==================================================================
	 */
	
	public float getDegrees() {
		return degrees;
	}

	public FlipAnimation setDegrees(float degrees) {
		this.degrees = degrees;
		return this;
	}

	public int getPivot() {
		return pivot;
	}

	public FlipAnimation setPivot(int pivot) {
		this.pivot = pivot;
		
		float pivotX = 0, pivotY = 0, viewWidth = targetView.getWidth(), viewHeight = targetView
				.getHeight();
		
		switch (orientation) {
		case Orientation.HORIZONTAL:
			switch (pivot) {
			case PIVOT_LEFT:
				pivotX = 0f;
				pivotY = viewHeight / 2;
				break;
			case PIVOT_RIGHT:
				pivotX = viewWidth;
				pivotY = viewHeight / 2;
				break;
			default:
				pivotX = viewWidth / 2;
				pivotY = viewHeight / 2;
				break;
			}
			break;

		case Orientation.VERTICAL:
			switch (pivot) {
			case PIVOT_TOP:
				pivotX = viewWidth / 2;
				pivotY = 0f;
				break;
			case PIVOT_BOTTOM:
				pivotX = viewWidth / 2;
				pivotY = viewHeight;
				break;
			default:
				pivotX = viewWidth / 2;
				pivotY = viewHeight / 2;
				break;
			}
			break;
		}
		
		ViewHelper.setPivotX(targetView, pivotX);
		ViewHelper.setPivotY(targetView, pivotY);
		
		return this;
	}

	public int getOrientation() {
		return orientation;
	}

	public FlipAnimation setOrientation(int orientation) {
		this.orientation = orientation;
		return this;
	}

} public class FlipToAnimation extends AnimationBase<FlipToAnimation>{

	public static final int PIVOT_CENTER = 0, PIVOT_LEFT = 1, PIVOT_RIGHT = 2, PIVOT_TOP = 3, PIVOT_BOTTOM = 4;

	View flipToView;
	int pivot, direction;
	float flipAngle;
	float originalRotation;
	int orientation = Orientation.HORIZONTAL;

	/*
	 * ==================================================================
	 * Constructor
	 * ==================================================================
	 */

	public FlipToAnimation(View targetView) {
		this.targetView = targetView;
		flipToView = null;
		pivot = PIVOT_CENTER;
		direction = Direction.DIRECTION_RIGHT;
		interpolator = new AccelerateDecelerateInterpolator();
		duration = Duration.DURATION_LONG;
		listener = null;
	}

	/*
	 * ==================================================================
	 * Override CombinableMethod
	 * ==================================================================
	 */

	@Override
	public void animate() {
		createAnimatorSet().start();
	}

	@Override
	public AnimatorSet createAnimatorSet() {
		ViewHelper.setClipChildren(targetView, false);

		flipAngle = 270f;
		if (pivot == PIVOT_CENTER) {
			flipAngle = 90f;
		}
		
		originalRotation = 0;

		flipToView.setLayoutParams(targetView.getLayoutParams());
		flipToView.setLeft(targetView.getLeft());
		flipToView.setTop(targetView.getTop());
		flipToView.setVisibility(View.VISIBLE);

		AnimatorSet flipToAnim = new AnimatorSet();
		switch (orientation) {
		case Orientation.HORIZONTAL:
			originalRotation = targetView.getRotationY();

			if (direction == Direction.DIRECTION_RIGHT) {
				flipToView.setRotationY(270f);
				flipToAnim.playSequentially(ObjectAnimator.ofFloat(targetView, View.ROTATION_Y, 0f, flipAngle),
						ObjectAnimator.ofFloat(flipToView, View.ROTATION_Y, 270f, 360f));
			} else {
				flipToView.setRotationY(-270f);
				flipToAnim.playSequentially(ObjectAnimator.ofFloat(targetView, View.ROTATION_Y, 0f, -flipAngle),
						ObjectAnimator.ofFloat(flipToView, View.ROTATION_Y, -270f, -360f));
			}

			break;

		case Orientation.VERTICAL:
			originalRotation = targetView.getRotationX();

			if (direction == Direction.DIRECTION_UP) {
				flipToView.setRotationX(270f);
				flipToAnim.playSequentially(ObjectAnimator.ofFloat(targetView, View.ROTATION_X, 0f, flipAngle),
						ObjectAnimator.ofFloat(flipToView, View.ROTATION_X, 270f, 360f));
			} else {
				flipToView.setRotationX(-270f);
				flipToAnim.playSequentially(ObjectAnimator.ofFloat(targetView, View.ROTATION_X, 0f, -flipAngle),
						ObjectAnimator.ofFloat(flipToView, View.ROTATION_X, -270f, -360f));
			}

			break;
		}

		flipToAnim.setInterpolator(interpolator);
		flipToAnim.setDuration(duration / 2);
		flipToAnim.addListener(new AnimatorListenerAdapter() {

			@Override
			public void onAnimationStart(Animator animation) {
				if (listener != null) {
					listener.onAnimationStart(animation);
				}
			}

			@Override
			public void onAnimationEnd(Animator animation) {
				targetView.setVisibility(View.INVISIBLE);
				switch (orientation) {
				case Orientation.HORIZONTAL:
					targetView.setRotationY(originalRotation);
					break;

				case Orientation.VERTICAL:
					targetView.setRotationX(originalRotation);
					break;
				}
		
				
				if (listener != null) {
					listener.onAnimationEnd(animation);
				}
			}

			@Override
			public void onAnimationCancel(Animator animation) {
				if (listener != null) {
					listener.onAnimationCancel(animation);
				}
			}

			@Override
			public void onAnimationRepeat(Animator animation) {
				if (listener != null) {
					listener.onAnimationRepeat(animation);
				}
			}

		});
		return flipToAnim;
	}


	@Override
	public FlipToAnimation setPivotX(int pivotX) {
		ViewHelper.setPivotX(targetView, pivotX);
		ViewHelper.setPivotX(flipToView, pivotX);

		return this;
	}

	@Override
	public FlipToAnimation setPivotY(int pivotY) {
		ViewHelper.setPivotY(targetView, pivotY);
		ViewHelper.setPivotY(flipToView, pivotY);

		return this;
	}

	/*
	 * ================================================================== 
	 * Getter And Setter
	 * ==================================================================
	 */

	public View getFlipToView() {
		return flipToView;
	}

	public FlipToAnimation setFlipToView(View flipToView) {
		this.flipToView = flipToView;
		return this;
	}

	public int getPivot() {
		return pivot;
	}

	public FlipToAnimation setPivot(int pivot) {
		this.pivot = pivot;

		flipAngle = 270f;
		
		float pivotX = 0, pivotY = 0, viewWidth = targetView.getWidth(), viewHeight = targetView.getHeight();

		switch (orientation) {
		case Orientation.HORIZONTAL:

			switch (pivot) {
			case PIVOT_LEFT:
				pivotX = 0f;
				pivotY = viewHeight / 2;
				break;
			case PIVOT_RIGHT:
				pivotX = viewWidth;
				pivotY = viewHeight / 2;
				break;
			default:
				pivotX = viewWidth / 2;
				pivotY = viewHeight / 2;
				flipAngle = 90f;
				break;
			}

			break;

		case Orientation.VERTICAL:

			switch (pivot) {
			case PIVOT_TOP:
				pivotX = viewWidth / 2;
				pivotY = 0f;
				break;
			case PIVOT_BOTTOM:
				pivotX = viewWidth / 2;
				pivotY = viewHeight;
				break;
			default:
				pivotX = viewWidth / 2;
				pivotY = viewHeight / 2;
				flipAngle = 90f;
				break;
			}

			break;
		}

		ViewHelper.setPivotX(targetView, pivotX);
		ViewHelper.setPivotY(targetView, pivotY);
		ViewHelper.setPivotX(flipToView, pivotX);
		ViewHelper.setPivotY(flipToView, pivotY);

		return this;
	}

	public int getDirection() {
		return direction;
	}

	public FlipToAnimation setDirection(int direction) {
		this.direction = direction;
		return this;
	}

	public int getOrientation() {
		return orientation;
	}

	public FlipToAnimation setOrientation(int orientation) {
		this.orientation = orientation;
		
		return this;
	}

} public class PathAnimation extends AnimationBase<PathAnimation> {

	private AnimatorPath path;
	
	/*
	 * ==================================================================
	 * Constructor
	 * ==================================================================
	 */
	
	public PathAnimation(View targetView) {
		this.targetView = targetView;
		interpolator = new AccelerateDecelerateInterpolator();
		duration = Duration.DURATION_LONG;
		listener = null;
	}
	

	public void setViewLoc(PathPoint newLoc) {
		targetView.setTranslationX(newLoc.mX);
		targetView.setTranslationY(newLoc.mY);
	}
	
	/*
	 * ==================================================================
	 * Override CombinableMethod
	 * ==================================================================
	 */

	@Override
	public void animate() {
		createAnimatorSet().start();
	}

	@Override
	public AnimatorSet createAnimatorSet() {
		ViewHelper.setClipChildren(targetView, false);

		if (path == null) {
			throw new IllegalArgumentException("You have to set up a AnimatorPath for PathAnimation!");
		}

		ObjectAnimator anim = ObjectAnimator.ofObject(this, "ViewLoc", new PathEvaluator(), path.getPoints().toArray());
		AnimatorSet animatorSet = new AnimatorSet();
		animatorSet.play(anim);
		animatorSet.setDuration(duration);
		animatorSet.setInterpolator(interpolator);
		if (listener != null) {
			animatorSet.addListener(listener);
		}

		return animatorSet;
	}

	/*
	 * ================================================================== 
	 * Getter And Setter
	 * ==================================================================
	 */
	
	public PathAnimation setPath(AnimatorPath path) {
		this.path = path;
		
		return this;
	}
	
} public class PuffAnimation extends AnimationBase<PuffAnimation> {
	
	float originalScaleX = 0f , originalScaleY = 0f , originalAlpha = 0f;
	int puffMode = PuffMode.IN;

	public interface PuffMode {
		public static final int IN = 0x01, OUT = 0x02;
	}

	/*
	 * ==================================================================
	 * Constructor
	 * ==================================================================
	 */
	
	public PuffAnimation(View targetView) {
		this.targetView = targetView;
		interpolator = new AccelerateDecelerateInterpolator();
		duration = Duration.DURATION_LONG;
		listener = null;
	}
	
	/*
	 * ==================================================================
	 * Override CombinableMethod
	 * ==================================================================
	 */

	@Override
	public void animate() {
		ViewHelper.setClipChildren(targetView, false);

		float scaleX = 0f, scaleY = 0f, alpha = 0f;
		
		switch (puffMode) {
		case PuffMode.IN:
			targetView.setScaleX(4f);
			targetView.setScaleY(4f);
			targetView.setAlpha(0f);

			scaleX = 1f;
			scaleY = 1f;
			alpha = 1f;
			break;

		case PuffMode.OUT:
			originalScaleX = targetView.getScaleX();
			originalScaleY = targetView.getScaleY();
			originalAlpha = targetView.getAlpha();

			scaleX = 4f;
			scaleY = 4f;
			alpha = 0f;
			break;
		}

		targetView.animate().scaleX(scaleX).scaleY(scaleY).alpha(alpha).setInterpolator(interpolator)
				.setDuration(duration).setListener(new AnimatorListenerAdapter() {

					@Override
					public void onAnimationStart(Animator animation) {
						switch (puffMode) {
						case PuffMode.IN:
							targetView.setVisibility(View.VISIBLE);
							break;

						case PuffMode.OUT:
							break;
						}
						
						if (listener != null) {
							listener.onAnimationStart(animation);
						}
			
					}

					@Override
					public void onAnimationEnd(Animator animation) {
						switch (puffMode) {
						case PuffMode.IN:
							break;

						case PuffMode.OUT:
							targetView.setVisibility(View.INVISIBLE);
							targetView.setScaleX(originalScaleX);
							targetView.setScaleY(originalScaleY);
							targetView.setAlpha(originalAlpha);
							break;
						}
						
						if (listener != null) {
							listener.onAnimationEnd(animation);
						}
					}
					
					@Override
					public void onAnimationCancel(Animator animation) {
						if (listener != null) {
							listener.onAnimationCancel(animation);
						}
					}
					
					@Override
					public void onAnimationRepeat(Animator animation) {
						if (listener != null) {
							listener.onAnimationRepeat(animation);
						}
					}
					
				});
	}

	@Override
	public AnimatorSet createAnimatorSet() {
		return null;
	}


	/*
	 * ================================================================== 
	 * Getter And Setter
	 * ==================================================================
	 */

	public int getPuffMode() {
		return puffMode;
	}

	public PuffAnimation setPuffMode(int puffMode) {
		this.puffMode = puffMode;
		
		return this;
	}

} public class RotateAnimation extends AnimationBase<RotateAnimation>{

	public static final int PIVOT_CENTER = 0, PIVOT_TOP_LEFT = 1, PIVOT_TOP_RIGHT = 2, PIVOT_BOTTOM_LEFT = 3,
			PIVOT_BOTTOM_RIGHT = 4;

	float degrees;
	int pivot;

	/*
	 * ==================================================================
	 * Constructor
	 * ==================================================================
	 */

	public RotateAnimation(View targetView) {
		this.targetView = targetView;
		degrees = 360;
		pivot = PIVOT_CENTER;
		interpolator = new AccelerateDecelerateInterpolator();
		duration = Duration.DURATION_LONG;
		listener = null;
	}

	/*
	 * ==================================================================
	 * Override CombinableMethod
	 * ==================================================================
	 */

	@Override
	public void animate() {
		createAnimatorSet().start();
	}

	@Override
	public AnimatorSet createAnimatorSet() {
		ViewHelper.setClipChildren(targetView, false);

		AnimatorSet rotationSet = new AnimatorSet();
		rotationSet.play(ObjectAnimator.ofFloat(targetView, View.ROTATION, targetView.getRotation() + degrees));
		rotationSet.setInterpolator(interpolator);
		rotationSet.setDuration(duration);
		if (listener != null) {
			rotationSet.addListener(listener);
		}

		return rotationSet;
	}

	
	/*
	 * ==================================================================
	 * Getter And Setter
	 * ==================================================================
	 */


	public RotateAnimation setPivot(int pivot) {
		this.pivot = pivot;

		float pivotX, pivotY, viewWidth = targetView.getWidth(), viewHeight = targetView.getHeight();
		switch (pivot) {
		case PIVOT_TOP_LEFT:
			pivotX = 1f;
			pivotY = 1f;
			break;
		case PIVOT_TOP_RIGHT:
			pivotX = viewWidth;
			pivotY = 1f;
			break;
		case PIVOT_BOTTOM_LEFT:
			pivotX = 1f;
			pivotY = viewHeight;
			break;
		case PIVOT_BOTTOM_RIGHT:
			pivotX = viewWidth;
			pivotY = viewHeight;
			break;
		default:
			pivotX = viewWidth / 2;
			pivotY = viewHeight / 2;
			break;
		}
		ViewHelper.setPivotX(targetView, pivotX);
		ViewHelper.setPivotY(targetView, pivotY);

		return this;
	}

	public RotateAnimation setDegrees(float degrees) {
		this.degrees = degrees;
		return this;
	}

} public class ScaleAnimation extends AnimationBase<ScaleAnimation>{
	
	/** X direction change of attribute values */
	protected float[] valuesX;
	
	/** Y direction change of attribute values */
	protected float[] valuesY;

	/*
	 * ==================================================================
	 * Constructor
	 * ==================================================================
	 */

	public ScaleAnimation(View targetView) {
		this.targetView = targetView;
		interpolator = new AccelerateDecelerateInterpolator();
		duration = Duration.DURATION_LONG;
		listener = null;
		
		valuesX = new float[]{ 0.0f , 1.0f };
		valuesY = new float[]{ 0.0f , 1.0f };
	}

	/*
	 * ==================================================================
	 * Override CombinableMethod
	 * ==================================================================
	 */

	@Override
	public void animate() {
		createAnimatorSet().start();
	}

	@Override
	public AnimatorSet createAnimatorSet() {
		/*targetView.setScaleX(0f);
		targetView.setScaleY(0f);*/
		targetView.setVisibility(View.VISIBLE);

		AnimatorSet scaleSet = new AnimatorSet();
		scaleSet.playTogether(ObjectAnimator.ofFloat(targetView, View.SCALE_X, valuesX ),
				ObjectAnimator.ofFloat(targetView, View.SCALE_Y, valuesY ));
		scaleSet.setInterpolator(interpolator);
		scaleSet.setDuration(duration);
		if (listener != null) {
			scaleSet.addListener(listener);
		}
		
		return scaleSet;
	}


	/*
	 * ==================================================================
	 * Getter And Setter
	 * ==================================================================
	 */

	public ScaleAnimation setValuesX(float[] valuesX) {
		this.valuesX = valuesX;
		
		return this;
	}

	public ScaleAnimation setValuesY(float[] valuesY) {
		this.valuesY = valuesY;
		
		return this;
	}


} public class ShakeAnimation extends AnimationBase<ShakeAnimation>{

	float shakeDistance;
	int numOfShakes, shakeCount = 0;
	
	private int orientation = Orientation.HORIZONTAL;
	
	/*
	 * ==================================================================
	 * Constructor
	 * ==================================================================
	 */

	public ShakeAnimation(View targetView) {
		this.targetView = targetView;
		shakeDistance = 20;
		numOfShakes = 2;
		interpolator = new AccelerateDecelerateInterpolator();
		duration = Duration.DURATION_LONG;
		listener = null;
	}

	/*
	 * ==================================================================
	 * Override CombinableMethod
	 * ==================================================================
	 */

	@Override
	public void animate() {
		createAnimatorSet().start();
	}

	@Override
	public AnimatorSet createAnimatorSet() {
		ViewHelper.setClipChildren(targetView, false);
		
		long singleShakeDuration = duration / numOfShakes / 2;
		if (singleShakeDuration == 0)
			singleShakeDuration = 1;
		final AnimatorSet shakeAnim = new AnimatorSet();
		switch (orientation) {
		case Orientation.HORIZONTAL:
			shakeAnim.playSequentially(ObjectAnimator.ofFloat(targetView, View.TRANSLATION_X, shakeDistance),
					ObjectAnimator.ofFloat(targetView, View.TRANSLATION_X, -shakeDistance),
//					ObjectAnimator.ofFloat(targetView, View.TRANSLATION_X, shakeDistance),
					ObjectAnimator.ofFloat(targetView, View.TRANSLATION_X, 0));
			break;

		case Orientation.VERTICAL:
			
			shakeAnim.playSequentially(ObjectAnimator.ofFloat(targetView,View.TRANSLATION_Y, shakeDistance),
					ObjectAnimator.ofFloat(targetView, View.TRANSLATION_Y, -shakeDistance),
//					ObjectAnimator.ofFloat(targetView, View.TRANSLATION_Y, shakeDistance),
					ObjectAnimator.ofFloat(targetView, View.TRANSLATION_Y, 0));
			
			break;
		}
		
		shakeAnim.setInterpolator(interpolator);
		shakeAnim.setDuration(singleShakeDuration);
		shakeAnim.addListener(new AnimatorListenerAdapter() {
			@Override
			public void onAnimationStart(Animator animation) {
				if (listener != null) {
					listener.onAnimationStart(animation);
				}
			}

			@Override
			public void onAnimationEnd(Animator animation) {
				shakeCount++;
				if (shakeCount == numOfShakes) {
					if (listener != null) {
						listener.onAnimationEnd(animation);
					}
				} else {
					shakeAnim.start();
				}
			}

			@Override
			public void onAnimationCancel(Animator animation) {
				if (listener != null) {
					listener.onAnimationCancel(animation);
				}
			}

			@Override
			public void onAnimationRepeat(Animator animation) {
				if (listener != null) {
					listener.onAnimationRepeat(animation);
				}
			}
		});
		return shakeAnim;
	}


	/*
	 * ================================================================== 
	 * Getter And Setter
	 * ==================================================================
	 */
	

	public int getOrientation() {
		return orientation;
	}

	public ShakeAnimation setOrientation(int orientation) {
		this.orientation = orientation;
		return this;
	}

	/**
	 * @return The maximum shake distance.
	 */
	public float getShakeDistance() {
		return shakeDistance;
	}

	/**
	 * @param shakeDistance
	 *            The maximum shake distance to set.
	 * @return ShakeAnimation
	 */
	public ShakeAnimation setShakeDistance(float shakeDistance) {
		this.shakeDistance = shakeDistance;
		return this;
	}

	/**
	 * @return The number of shakes.
	 */
	public int getNumOfShakes() {
		return numOfShakes;
	}

	/**
	 * @param numOfShakes
	 *            The number of shakes to set.
	 * @return ShakeAnimation
	 */
	public ShakeAnimation setNumOfShakes(int numOfShakes) {
		this.numOfShakes = numOfShakes;
		return this;
	}

} public class SlideAnimation extends AnimationBase<SlideAnimation>{

	int direction;
	int slideMode = SlideMode.IN;
	ObjectAnimator slideAnim;

	/**
	 * Slide animation mode, to enter or exit
	 * 
	 * @author Robin
	 *
	 */
	public interface SlideMode {
		public static final int IN = 0x01, OUT = 0x02;
	}

	/*
	 * ==================================================================
	 * Constructor
	 * ==================================================================
	 */

	public SlideAnimation(View targetView) {
		this.targetView = targetView;
		direction = Direction.DIRECTION_LEFT;
		interpolator = new AccelerateDecelerateInterpolator();
		duration = Duration.DURATION_LONG;
		listener = null;
		slideAnim = null;
	}

	/*
	 * ==================================================================
	 * Override CombinableMethod
	 * ==================================================================
	 */

	@Override
	public void animate() {
		createAnimatorSet().start();
	}

	@Override
	public AnimatorSet createAnimatorSet() {
		ViewHelper.setClipChildren(targetView, false);
		
		ViewGroup rootView = (ViewGroup) targetView.getRootView();
		
		int[] locationView = new int[2];
		targetView.getLocationOnScreen(locationView);

		switch (slideMode) {
		case SlideMode.IN:

			switch (direction) {
			case Direction.DIRECTION_LEFT:
				slideAnim = ObjectAnimator.ofFloat(targetView, View.X, -locationView[0] - targetView.getWidth(),
						targetView.getX());
				break;
			case Direction.DIRECTION_RIGHT:
				slideAnim = ObjectAnimator.ofFloat(targetView, View.X, rootView.getRight(), targetView.getX());
				break;
			case Direction.DIRECTION_UP:
				slideAnim = ObjectAnimator.ofFloat(targetView, View.Y, -locationView[1] - targetView.getHeight(),
						targetView.getY());
				break;
			case Direction.DIRECTION_DOWN:
				slideAnim = ObjectAnimator.ofFloat(targetView, View.Y, rootView.getBottom(), targetView.getY());
				break;
			default:
				break;
			}

			break;

		case SlideMode.OUT:

			switch (direction) {
			case Direction.DIRECTION_LEFT:
				slideAnim = ObjectAnimator.ofFloat(targetView, View.X, -locationView[0] - targetView.getWidth());
				break;
			case Direction.DIRECTION_RIGHT:
				slideAnim = ObjectAnimator.ofFloat(targetView, View.X, rootView.getRight());
				break;
			case Direction.DIRECTION_UP:
				slideAnim = ObjectAnimator.ofFloat(targetView, View.Y, -locationView[1] - targetView.getHeight());
				break;
			case Direction.DIRECTION_DOWN:
				slideAnim = ObjectAnimator.ofFloat(targetView, View.Y, rootView.getBottom());
				break;
			default:
				break;
			}

			break;
		}

		AnimatorSet slideSet = new AnimatorSet();
		slideSet.play(slideAnim);
		slideSet.setInterpolator(interpolator);
		slideSet.setDuration(duration);
		slideSet.addListener(new AnimatorListenerAdapter() {

			@Override
			public void onAnimationStart(Animator animation) {
				switch (slideMode) {
				case SlideMode.IN:
					targetView.setVisibility(View.VISIBLE);
					if (listener != null) {
						listener.onAnimationStart(animation);
					}
					break;

				case SlideMode.OUT:
					break;
				}

			}

			@Override
			public void onAnimationEnd(Animator animation) {
				switch (slideMode) {
				case SlideMode.IN:
					break;

				case SlideMode.OUT:
					targetView.setVisibility(View.INVISIBLE);
					slideAnim.reverse();
					break;
				}
				if (listener != null) {
					listener.onAnimationEnd(animation);
				}
			}

			@Override
			public void onAnimationCancel(Animator animation) {
				if (listener != null) {
					listener.onAnimationCancel(animation);
				}
			}

			@Override
			public void onAnimationRepeat(Animator animation) {
				if (listener != null) {
					listener.onAnimationRepeat(animation);
				}
			}
		});
		return slideSet;
	}

	/*
	 * ================================================================== 
	 * Getter And Setter
	 * ==================================================================
	 */

	public SlideAnimation setDirection(int direction) {
		this.direction = direction;
		return this;
	}

	public int getSlideMode() {
		return slideMode;
	}

	public SlideAnimation setSlideMode(int slideMode) {
		this.slideMode = slideMode;

		return this;
	}

} public class SlideUnderneathAnimation extends AnimationBase<SlideUnderneathAnimation>{

	int direction;
	int slideMode = SlideMode.IN;
	ObjectAnimator slideAnim;

	/**
	 * Slide animation mode, to enter or exit
	 * 
	 * @author Robin
	 *
	 */
	public interface SlideMode {
		public static final int IN = 0x01, OUT = 0x02;
	}

	/*
	 * ==================================================================
	 * Constructor
	 * ==================================================================
	 */

	public SlideUnderneathAnimation(View targetView) {
		this.targetView = targetView;
		direction = Direction.DIRECTION_LEFT;
		interpolator = new AccelerateDecelerateInterpolator();
		duration = Duration.DURATION_LONG;
		listener = null;
		slideAnim = null;
	}

	/*
	 * ==================================================================
	 * Override CombinableMethod
	 * ==================================================================
	 */

	@Override
	public void animate() {
		createAnimatorSet().start();
	}

	@Override
	public AnimatorSet createAnimatorSet() {
		ViewHelper.setClipChildren(targetView, true);

		final ViewGroup parentView = (ViewGroup) targetView.getParent();
		final FrameLayout slideFrame = new FrameLayout(targetView.getContext());
		final int positionView = parentView.indexOfChild(targetView);
		slideFrame.setLayoutParams(targetView.getLayoutParams());
		slideFrame.setClipChildren(true);
		parentView.removeView(targetView);
		slideFrame.addView(targetView);
		parentView.addView(slideFrame, positionView);

		switch (slideMode) {
		case SlideMode.IN:

			switch (direction) {
			case Direction.DIRECTION_LEFT:
				targetView.setTranslationX(-targetView.getWidth());
				slideAnim = ObjectAnimator.ofFloat(targetView, View.TRANSLATION_X, slideFrame.getX());
				break;
			case Direction.DIRECTION_RIGHT:
				targetView.setTranslationX(targetView.getWidth());
				slideAnim = ObjectAnimator.ofFloat(targetView, View.TRANSLATION_X, slideFrame.getX());
				break;
			case Direction.DIRECTION_UP:
				targetView.setTranslationY(-targetView.getHeight());
				slideAnim = ObjectAnimator.ofFloat(targetView, View.TRANSLATION_Y, slideFrame.getY());
				break;
			case Direction.DIRECTION_DOWN:
				targetView.setTranslationY(targetView.getHeight());
				slideAnim = ObjectAnimator.ofFloat(targetView, View.TRANSLATION_Y, slideFrame.getY());
				break;
			default:
				break;
			}
			break;

		case SlideMode.OUT:

			switch (direction) {
			case Direction.DIRECTION_LEFT:
				slideAnim = ObjectAnimator.ofFloat(targetView, View.TRANSLATION_X,
						targetView.getTranslationX() - targetView.getWidth());
				break;
			case Direction.DIRECTION_RIGHT:
				slideAnim = ObjectAnimator.ofFloat(targetView, View.TRANSLATION_X,
						targetView.getTranslationX() + targetView.getWidth());
				break;
			case Direction.DIRECTION_UP:
				slideAnim = ObjectAnimator.ofFloat(targetView, View.TRANSLATION_Y,
						targetView.getTranslationY() - targetView.getHeight());
				break;
			case Direction.DIRECTION_DOWN:
				slideAnim = ObjectAnimator.ofFloat(targetView, View.TRANSLATION_Y,
						targetView.getTranslationY() + targetView.getHeight());
				break;
			default:
				break;
			}

			break;
		}

		AnimatorSet slideSet = new AnimatorSet();
		slideSet.play(slideAnim);
		slideSet.setInterpolator(interpolator);
		slideSet.setDuration(duration);
		slideAnim.addListener(new AnimatorListenerAdapter() {

			@Override
			public void onAnimationStart(Animator animation) {
				switch (slideMode) {
				case SlideMode.IN:
					targetView.setVisibility(View.VISIBLE);
					break;

				case SlideMode.OUT:
					break;
				}

				if (listener != null) {
					listener.onAnimationStart(animation);
				}
			}

			@Override
			public void onAnimationEnd(Animator animation) {
				switch (slideMode) {
				case SlideMode.IN:
					slideFrame.removeAllViews();
					parentView.removeView(slideFrame);
					targetView.setLayoutParams(slideFrame.getLayoutParams());
					parentView.addView(targetView, positionView);
					break;

				case SlideMode.OUT:
					targetView.setVisibility(View.INVISIBLE);
					//slideAnim.reverse();
					slideFrame.removeAllViews();
					parentView.removeView(slideFrame);
					targetView.setLayoutParams(slideFrame.getLayoutParams());
					parentView.addView(targetView, positionView);
					break;
				}

				if (listener != null) {
					listener.onAnimationEnd(animation);
				}
			}

			@Override
			public void onAnimationCancel(Animator animation) {
				if (listener != null) {
					listener.onAnimationCancel(animation);
				}
			}

			@Override
			public void onAnimationRepeat(Animator animation) {
				if (listener != null) {
					listener.onAnimationRepeat(animation);
				}
			}
		});

		return slideSet;
	}


	/*
	 * ================================================================== 
	 * Getter And Setter
	 * ==================================================================
	 */

	public SlideUnderneathAnimation setDirection(int direction) {
		this.direction = direction;
		return this;
	}

	public int getSlideMode() {
		return slideMode;
	}

	public SlideUnderneathAnimation setSlideMode(int slideMode) {
		this.slideMode = slideMode;

		return this;
	}

} public class SvgAnimationView extends View {
    /**
     * Logging tag.
     */
    public static final String LOG_TAG = "PathView";
    /**
     * The paint for the path.
     */
    private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    /**
     * Utils to catch the paths from the svg.
     */
    private final SvgHelper svgUtils = new SvgHelper(paint);
    /**
     * All the paths provided to the view. Both from Path and Svg.
     */
    private List<SvgHelper.SvgPath> paths = new ArrayList<SvgHelper.SvgPath>(0);
    /**
     * This is a lock before the view is redrawn
     * or resided it must be synchronized with this object.
     */
    private final Object mSvgLock = new Object();
    /**
     * Thread for working with the object above.
     */
    private Thread mLoader;

    /**
     * The svg image from the raw directory.
     */
    private int svgResourceId;
    /**
     * Object that build the animation for the path.
     */
    private AnimatorBuilder animatorBuilder;
    /**
     * The progress of the drawing.
     */
    private float progress = 0f;

    /**
     * If the used colors are from the svg or from the set color.
     */
    private boolean naturalColors;
    /**
     * If the view is filled with its natural colors after path drawing.
     */
    private boolean fillAfter;
    /**
     * The width of the view.
     */
    private int width;
    /**
     * The height of the view.
     */
    private int height;

    /**
     * Default constructor.
     *
     * @param context The Context of the application.
     */
    public SvgAnimationView(Context context) {
        this(context, null);
    }

    /**
     * Default constructor.
     *
     * @param context The Context of the application.
     * @param attrs   attributes provided from the resources.
     */
    public SvgAnimationView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * Default constructor.
     *
     * @param context  The Context of the application.
     * @param attrs    attributes provided from the resources.
     * @param defStyle Default style.
     */
    public SvgAnimationView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        paint.setStyle(Paint.Style.STROKE);
        getFromAttributes(context, attrs);
    }

    /**
     * Get all the fields from the attributes .
     *
     * @param context The Context of the application.
     * @param attrs   attributes provided from the resources.
     */
    private void getFromAttributes(Context context, AttributeSet attrs) {
        /*final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PathView);
        try {
            if (a != null) {
                paint.setColor(a.getColor(R.styleable.PathView_pathColor, 0xff00ff00));
                paint.setStrokeWidth(a.getFloat(R.styleable.PathView_pathWidth, 8.0f));
                svgResourceId = a.getResourceId(R.styleable.PathView_svg, 0);
            }
        } finally {
            if (a != null) {
                a.recycle();
            }
        }*/
        
        paint.setColor(0xff00ff00);
        paint.setStrokeWidth(8.0f);
        svgResourceId =0;
    }

    /**
     * Set paths to be drawn and animated.
     *
     * @param paths - Paths that can be drawn.
     */
    public void setPaths(final List<Path> paths) {
        for (Path path : paths) {
            this.paths.add(new SvgHelper.SvgPath(path, paint));
        }
        synchronized (mSvgLock) {
            updatePathsPhaseLocked();
        }
    }

    /**
     * Set path to be drawn and animated.
     *
     * @param path - Paths that can be drawn.
     */
    public void setPath(final Path path) {
        paths.add(new SvgHelper.SvgPath(path, paint));
        synchronized (mSvgLock) {
            updatePathsPhaseLocked();
        }
    }

    /**
     * Animate this property. It is the percentage of the path that is drawn.
     * It must be [0,1].
     *
     * @param percentage float the percentage of the path.
     */
    public void setPercentage(float percentage) {
        if (percentage < 0.0f || percentage > 1.0f) {
            throw new IllegalArgumentException("setPercentage not between 0.0f and 1.0f");
        }
        progress = percentage;
        synchronized (mSvgLock) {
            updatePathsPhaseLocked();
        }
        invalidate();
    }

    /**
     * This refreshes the paths before draw and resize.
     */
    private void updatePathsPhaseLocked() {
        final int count = paths.size();
        for (int i = 0; i < count; i++) {
            SvgHelper.SvgPath svgPath = paths.get(i);
            svgPath.path.reset();
            svgPath.measure.getSegment(0.0f, svgPath.length * progress, svgPath.path, true);
            // Required only for Android 4.4 and earlier
            svgPath.path.rLineTo(0.0f, 0.0f);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        synchronized (mSvgLock) {
            canvas.save();
            canvas.translate(getPaddingLeft(), getPaddingTop());
            final int count = paths.size();
            for (int i = 0; i < count; i++) {
                final SvgHelper.SvgPath svgPath = paths.get(i);
                final Path path = svgPath.path;
                final Paint paint1 = naturalColors ? svgPath.paint : paint;
                canvas.drawPath(path, paint1);
            }
            fillAfter(canvas);
            canvas.restore();
        }
    }

    /**
     * If there is svg , the user called setFillAfter(true) and the progress is finished.
     *
     * @param canvas Draw to this canvas.
     */
    private void fillAfter(final Canvas canvas) {
        if (svgResourceId != 0 && fillAfter && progress == 1f) {
            svgUtils.drawSvgAfter(canvas, width, height);
        }
    }

    @Override
    protected void onSizeChanged(final int w, final int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        if (mLoader != null) {
            try {
                mLoader.join();
            } catch (InterruptedException e) {
                Log.e(LOG_TAG, "Unexpected error", e);
            }
        }
        if (svgResourceId != 0) {
            mLoader = new Thread(new Runnable() {
                @Override
                public void run() {

                    svgUtils.load(getContext(), svgResourceId);

                    synchronized (mSvgLock) {
                        width = w - getPaddingLeft() - getPaddingRight();
                        height = h - getPaddingTop() - getPaddingBottom();
                        paths = svgUtils.getPathsForViewport(width, height);
                        updatePathsPhaseLocked();
                    }
                }
            }, "SVG Loader");
            mLoader.start();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (svgResourceId != 0) {
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
            setMeasuredDimension(widthSize, heightSize);
            return;
        }

        int desiredWidth = 0;
        int desiredHeight = 0;
        final float strokeWidth = paint.getStrokeWidth() / 2;
        for (SvgHelper.SvgPath path : paths) {
            desiredWidth += path.bounds.left + path.bounds.width() + strokeWidth;
            desiredHeight += path.bounds.top + path.bounds.height() + strokeWidth;
        }
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(widthMeasureSpec);

        int measuredWidth, measuredHeight;

        if (widthMode == MeasureSpec.AT_MOST) {
            measuredWidth = desiredWidth;
        } else {
            measuredWidth = widthSize;
        }

        if (heightMode == MeasureSpec.AT_MOST) {
            measuredHeight = desiredHeight;
        } else {
            measuredHeight = heightSize;
        }

        setMeasuredDimension(measuredWidth, measuredHeight);
    }

    /**
     * If the real svg need to be drawn after the path animation.
     *
     * @param fillAfter - boolean if the view needs to be filled after path animation.
     */
    public void setFillAfter(final boolean fillAfter) {
        this.fillAfter = fillAfter;
    }

    /**
     * If you want to use the colors from the svg.
     */
    public void useNaturalColors() {
        naturalColors = true;
    }

    /**
     * Animator for the paths of the view.
     *
     * @return The AnimatorBuilder to build the animation.
     */
    public AnimatorBuilder getPathAnimator() {
        if (animatorBuilder == null) {
            animatorBuilder = new AnimatorBuilder(this);
        }
        return animatorBuilder;
    }

    /**
     * Get the path color.
     *
     * @return The color of the paint.
     */
    public int getPathColor() {
        return paint.getColor();
    }

    /**
     * Set the path color.
     *
     * @param color -The color to set to the paint.
     */
    public void setPathColor(final int color) {
        paint.setColor(color);
    }

    /**
     * Get the path width.
     *
     * @return The width of the paint.
     */
    public float getPathWidth() {
        return paint.getStrokeWidth();
    }

    /**
     * Set the path width.
     *
     * @param width - The width of the path.
     */
    public void setPathWidth(final float width) {
        paint.setStrokeWidth(width);
    }

    /**
     * Get the svg resource id.
     *
     * @return The svg raw resource id.
     */
    public int getSvgResource() {
        return svgResourceId;
    }

    /**
     * Set the svg resource id.
     *
     * @param svgResource - The resource id of the raw svg.
     */
    public void setSvgResource(int svgResource) {
        svgResourceId = svgResource;
    }

    /**
     * Object for building the animation of the path of this view.
     */
    public static class AnimatorBuilder {
        /**
         * Duration of the animation.
         */
        private int duration = 350;
        /**
         * Interpolator for the time of the animation.
         */
        private Interpolator interpolator;
        /**
         * The delay before the animation.
         */
        private int delay = 0;
        /**
         * ObjectAnimator that constructs the animation.
         */
        private final ObjectAnimator anim;
        /**
         * Listener called before the animation.
         */
        private ListenerStart listenerStart;
        /**
         * Listener after the animation.
         */
        private ListenerEnd animationEnd;
        /**
         * Animation listener.
         */
        private PathViewAnimatorListener pathViewAnimatorListener;

        /**
         * Default constructor.
         *
         * @param pathView The view that must be animated.
         */
        public AnimatorBuilder(final SvgAnimationView pathView) {
            anim = ObjectAnimator.ofFloat(pathView, "percentage", 0.0f, 1.0f);
        }

        /**
         * Set the duration of the animation.
         *
         * @param duration - The duration of the animation.
         * @return AnimatorBuilder.
         */
        public AnimatorBuilder duration(final int duration) {
            this.duration = duration;
            return this;
        }

        /**
         * Set the Interpolator.
         *
         * @param interpolator - Interpolator.
         * @return AnimatorBuilder.
         */
        public AnimatorBuilder interpolator(final Interpolator interpolator) {
            this.interpolator = interpolator;
            return this;
        }

        /**
         * The delay before the animation.
         *
         * @param delay - int the delay
         * @return AnimatorBuilder.
         */
        public AnimatorBuilder delay(final int delay) {
            this.delay = delay;
            return this;
        }

        /**
         * Set a listener before the start of the animation.
         *
         * @param listenerStart an interface called before the animation
         * @return AnimatorBuilder.
         */
        public AnimatorBuilder listenerStart(final ListenerStart listenerStart) {
            this.listenerStart = listenerStart;
            if (pathViewAnimatorListener == null) {
                pathViewAnimatorListener = new PathViewAnimatorListener();
                anim.addListener(pathViewAnimatorListener);
            }
            return this;
        }

        /**
         * Set a listener after of the animation.
         *
         * @param animationEnd an interface called after the animation
         * @return AnimatorBuilder.
         */
        public AnimatorBuilder listenerEnd(final ListenerEnd animationEnd) {
            this.animationEnd = animationEnd;
            if (pathViewAnimatorListener == null) {
                pathViewAnimatorListener = new PathViewAnimatorListener();
                anim.addListener(pathViewAnimatorListener);
            }
            return this;
        }

        /**
         * Starts the animation.
         */
        public void start() {
            anim.setDuration(duration);
            anim.setInterpolator(interpolator);
            anim.setStartDelay(delay);
            anim.start();
        }

        /**
         * Animation listener to be able to provide callbacks for the caller.
         */
        private class PathViewAnimatorListener implements Animator.AnimatorListener {

            @Override
            public void onAnimationStart(Animator animation) {
                if (listenerStart != null) listenerStart.onAnimationStart();
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                if (animationEnd != null) animationEnd.onAnimationEnd();
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        }

        /**
         * Called when the animation start.
         */
        public interface ListenerStart {
            /**
             * Called when the path animation start.
             */
            void onAnimationStart();
        }

        /**
         * Called when the animation end.
         */
        public interface ListenerEnd {
            /**
             * Called when the path animation end.
             */
            void onAnimationEnd();
        }
    }
} public class TelescopicAnimation extends AnimationBase<TelescopicAnimation> {
	
	int telescopicMode = TelescopicMode.IN;
	int telescopicTargetMode = TelescopicTargetMode.HEIGHT;
	int start,end;

	public interface TelescopicMode {
		public static final int IN = 0x01, OUT = 0x02;
	}
	
	public interface TelescopicTargetMode {
		public static final int WIDTH = 0x03, HEIGHT = 0x04;
	}
	
	/*
	 * ==================================================================
	 * Constructor
	 * ==================================================================
	 */
	
	public TelescopicAnimation(View targetView) {
		this.targetView = targetView;
		interpolator = new AccelerateDecelerateInterpolator();
		duration = Duration.DURATION_LONG;
		listener = null;
	
	}
	
	/*
	 * ==================================================================
	 * Override CombinableMethod
	 * ==================================================================
	 */

	@Override
	public void animate() {
		createAnimatorSet().start();
	}

	@Override
	public AnimatorSet createAnimatorSet() {
		ViewHelper.setClipChildren(targetView, true);
		
		final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        targetView.measure(widthSpec, heightSpec);
		
		switch (telescopicTargetMode) {
		case TelescopicTargetMode.WIDTH:
			switch (telescopicMode) {
			case TelescopicMode.IN:
				start = 0;
				if (end == 0) {
					end = targetView.getMeasuredWidth();
				}
				break;

			case TelescopicMode.OUT:
				start = targetView.getMeasuredWidth();
				end = 0;
				break;
			}

			break;

		case TelescopicTargetMode.HEIGHT:
			switch (telescopicMode) {
			case TelescopicMode.IN:
				start = 0;
				if (end == 0) {
					end = targetView.getMeasuredHeight();
				}
				break;

			case TelescopicMode.OUT:
				start = targetView.getMeasuredHeight();
				end = 0;
				break;
			}
			break;
		}

		
		ValueAnimator animator = ValueAnimator.ofInt(start, end);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int value = (Integer) valueAnimator.getAnimatedValue();

                ViewGroup.LayoutParams layoutParams = targetView.getLayoutParams();
                switch (telescopicTargetMode) {
				case TelescopicTargetMode.WIDTH:
				       layoutParams.width = value;
					break;

				case TelescopicTargetMode.HEIGHT:
				       layoutParams.height = value;
					break;
				}
         
                targetView.setLayoutParams(layoutParams);
            }
        });
        
        animator.addListener(new Animator.AnimatorListener() {
			
			@Override
			public void onAnimationStart(Animator animation) {
				switch (telescopicMode) {
				case TelescopicMode.IN:
					targetView.setVisibility(View.VISIBLE);
					break;

				case TelescopicMode.OUT:
					break;
				}
				
				if (listener != null) {
					listener.onAnimationStart(animation);
				}
			}
			
			@Override
			public void onAnimationRepeat(Animator animation) {
				if (listener != null) {
					listener.onAnimationRepeat(animation);
				}
			}
			
			@Override
			public void onAnimationEnd(Animator animation) {
				switch (telescopicMode) {
				case TelescopicMode.IN:
					break;

				case TelescopicMode.OUT:
					targetView.setVisibility(View.GONE);
					break;
				}
				
				if (listener != null) {
					listener.onAnimationEnd(animation);
				}
			}
			
			@Override
			public void onAnimationCancel(Animator animation) {
				if (listener != null) {
					listener.onAnimationCancel(animation);
				}
			}
		});
        
        AnimatorSet animatorSet =new AnimatorSet();
        animatorSet.play(animator);
        animatorSet.setDuration(duration);
        animatorSet.setInterpolator(interpolator);
		
		return animatorSet;
	}


	
	/*
	 * ================================================================== 
	 * Getter And Setter
	 * ==================================================================
	 */
	
	public int getTelescopicMode() {
		return telescopicMode;
	}

	public TelescopicAnimation setTelescopicMode(int telescopicMode) {
		this.telescopicMode = telescopicMode;
		
		return this;
	}

	public int getTelescopicTargetMode() {
		return telescopicTargetMode;
	}

	public TelescopicAnimation setTelescopicTargetMode(int telescopicTargetMode) {
		this.telescopicTargetMode = telescopicTargetMode;
		
		return this;
	}

	public int getStart() {
		return start;
	}

	public TelescopicAnimation setStart(int start) {
		this.start = start;
		
		return this;
	}

	public int getEnd() {
		return end;
	}

	public TelescopicAnimation setEnd(int end) {
		this.end = end;
		
		return this;
	}


} public class TransferAnimation extends AnimationBase<TransferAnimation>{

	View destinationView;
	int transX, transY;
	float scaleX, scaleY;
	ViewGroup parentView;

	/*
	 * ==================================================================
	 * Constructor
	 * ==================================================================
	 */

	public TransferAnimation(View targetView) {
		this.targetView = targetView;
		destinationView = null;
		interpolator = new AccelerateDecelerateInterpolator();
		duration = Duration.DURATION_LONG;
		listener = null;
	}

	/*
	 * ==================================================================
	 * Override CombinableMethod
	 * ==================================================================
	 */

	@Override
	public void animate() {
		ViewHelper.setClipChildren(targetView, false);

		parentView = (ViewGroup) targetView.getParent();

		targetView.animate().scaleX(scaleX).scaleY(scaleY).translationX(transX).translationY(transY)
				.setInterpolator(interpolator).setDuration(duration).setListener(new AnimatorListenerAdapter() {
					@Override
					public void onAnimationStart(Animator animation) {
						if (listener != null) {
							listener.onAnimationStart(animation);
						}
					}

					@Override
					public void onAnimationEnd(Animator animation) {
						if (listener != null) {
							listener.onAnimationEnd(animation);
						}
					}
					
					@Override
					public void onAnimationCancel(Animator animation) {
						if (listener != null) {
							listener.onAnimationCancel(animation);
						}
					}
					
					@Override
					public void onAnimationRepeat(Animator animation) {
						if (listener != null) {
							listener.onAnimationRepeat(animation);
						}
					}
				});
	}

	@Override
	public AnimatorSet createAnimatorSet() {
		return null;
	}


	/*
	 * ================================================================== 
	 * Getter And Setter
	 * ==================================================================
	 */

	/**
	 * @return The destination view to transfer the original view to.
	 */
	public View getDestinationView() {
		return destinationView;
	}

	/**
	 * @param The
	 *            destination view to set to transfer the original view to.
	 * @return TransferAnimation
	 */
	public TransferAnimation setDestinationView(View destinationView) {
		this.destinationView = destinationView;

		scaleX = (float) destinationView.getWidth() / ((float) targetView.getWidth());
		scaleY = (float) destinationView.getHeight() / ((float) targetView.getHeight());
		
		int[] locationDest = new int[2], locationView = new int[2];
		targetView.getLocationOnScreen(locationView);
		destinationView.getLocationOnScreen(locationDest);
		transX = locationDest[0] - locationView[0];
		transY = locationDest[1] - locationView[1];
		transX = transX - targetView.getWidth() / 2 + destinationView.getWidth() / 2;
		transY = transY - targetView.getHeight() / 2 + destinationView.getHeight() / 2;

		return this;
	}

	public int getTransX() {
		return transX;
	}

	public void setTransX(int transX) {
		this.transX = transX;
	}

	public int getTransY() {
		return transY;
	}

	public void setTransY(int transY) {
		this.transY = transY;
	}

	public float getScaleX() {
		return scaleX;
	}

	public void setScaleX(float scaleX) {
		this.scaleX = scaleX;
	}

	public float getScaleY() {
		return scaleY;
	}

	public void setScaleY(float scaleY) {
		this.scaleY = scaleY;
	}
	
	

}
import com.xdroid.animation.anim.AlphaAnimation;
import com.xdroid.animation.anim.BlindAnimation;
import com.xdroid.animation.anim.ColorAnimation;
import com.xdroid.animation.anim.CombinationAnimation;
import com.xdroid.animation.anim.FlipAnimation;
import com.xdroid.animation.anim.FlipToAnimation;
import com.xdroid.animation.anim.PathAnimation;
import com.xdroid.animation.anim.PuffAnimation;
import com.xdroid.animation.anim.RotateAnimation;
import com.xdroid.animation.anim.ScaleAnimation;
import com.xdroid.animation.anim.ShakeAnimation;
import com.xdroid.animation.anim.SlideAnimation;
import com.xdroid.animation.anim.SlideUnderneathAnimation;
import com.xdroid.animation.anim.SvgAnimationView;
import com.xdroid.animation.anim.TelescopicAnimation;
import com.xdroid.animation.anim.TransferAnimation;
import android.content.Context;
import android.view.View;
package com.xdroid.animation;



public class AnimationKit {

	/*
	 * private static volatile AnimationKit INSTANCE = null;
	 * 
	 * public static AnimationKit getInstance() { if (INSTANCE == null) {
	 * synchronized (AnimationKit.class) { if (INSTANCE == null) { INSTANCE =
	 * new AnimationKit(); } } } return INSTANCE; }
	 */

	/*public static <T> void scale(View targetView, T... params) {
		if (targetView == null) {
			return;
		}
		ScaleAnimation mScaleInAnimation = new ScaleAnimation(targetView);

		if (params.length >= 0) {
			for (int i = 0; i < params.length; i++) {
				if (params[i] instanceof Integer) {
					mScaleInAnimation.setDuration((Integer) params[i]);
				} else if (params[i] instanceof TimeInterpolator) {
					mScaleInAnimation.setInterpolator((TimeInterpolator) params[i]);
				} else if (params[i] instanceof AnimatorListener) {
					mScaleInAnimation.setListener((AnimatorListener) params[i]);
				} else if (params[i] instanceof float[]) {
					mScaleInAnimation.setValuesX((float[]) params[i]).setValuesY((float[]) params[i]);
				}
			}
			mScaleInAnimation.animate();
		}

	}*/

	public static AlphaAnimation createAlphaAnimation(View targetView) {
		return new AlphaAnimation(targetView);
	}

	public static BlindAnimation createBlindAnimation(View targetView) {
		return new BlindAnimation(targetView);
	}

	public static ColorAnimation createColorAnimation(View targetView) {
		return new ColorAnimation(targetView);
	}

	public static CombinationAnimation createCombinationAnimation() {
		return new CombinationAnimation();
	}

	public static FlipAnimation createFlipAnimation(View targetView) {
		return new FlipAnimation(targetView);
	}

	public static FlipToAnimation createFlipToAnimation(View targetView) {
		return new FlipToAnimation(targetView);
	}

	public static PathAnimation createPathAnimation(View targetView) {
		return new PathAnimation(targetView);
	}

	public static PuffAnimation createPuffAnimation(View targetView) {
		return new PuffAnimation(targetView);
	}

	public static RotateAnimation createRotateAnimation(View targetView) {
		return new RotateAnimation(targetView);
	}

	public static ScaleAnimation createScaleAnimation(View targetView) {
		return new ScaleAnimation(targetView);
	}

	public static ShakeAnimation createShakeAnimation(View targetView) {
		return new ShakeAnimation(targetView);
	}

	public static SlideAnimation createSlideAnimation(View targetView) {
		return new SlideAnimation(targetView);
	}

	public static SlideUnderneathAnimation createSlideUnderneathAnimation(View targetView) {