code: package io.virtualapp.effects;
  
  import java.util.Random;
  
  import android.animation.ValueAnimator;
  import android.graphics.Bitmap;
  import android.graphics.Canvas;
  import android.graphics.Color;
  import android.graphics.Paint;
  import android.graphics.Rect;
  import android.view.View;
  import android.view.animation.AccelerateInterpolator;
  import android.view.animation.Interpolator;
  
  import io.virtualapp.VApp;
  import io.virtualapp.abs.ui.VUiKit;
  
  public class ExplosionAnimator extends ValueAnimator {
  
  	private static final Interpolator DEFAULT_INTERPOLATOR = new AccelerateInterpolator(0.6f);
  	private static final float END_VALUE = 1.4f;
  	private static final float X = VUiKit.dpToPx(VApp.getApp(), 5);
  	private static final float Y = VUiKit.dpToPx(VApp.getApp(), 20);
  	private static final float V = VUiKit.dpToPx(VApp.getApp(), 2);
  	private static final float W = VUiKit.dpToPx(VApp.getApp(), 1);
  	static long DEFAULT_DURATION = 0x450;
  	private Paint mPaint;
  	private Particle[] mParticles;
  	private Rect mBound;
  	private View mContainer;
  
  	public ExplosionAnimator(View container, Bitmap bitmap, Rect bound) {
  		mPaint = new Paint();
  		mBound = new Rect(bound);
  		int partLen = 15;
  		mParticles = new Particle[partLen * partLen];
  		Random random = new Random(System.currentTimeMillis());
  		int w = bitmap.getWidth() / (partLen + 2);
  		int h = bitmap.getHeight() / (partLen + 2);
  		for (int i = 0; i < partLen; i++) {
  			for (int j = 0; j < partLen; j++) {
  				mParticles[(i * partLen) + j] = generateParticle(bitmap.getPixel((j + 1) * w, (i + 1) * h), random);
  			}
  		}
  		mContainer = container;
  		setFloatValues(0f, END_VALUE);
  		setInterpolator(DEFAULT_INTERPOLATOR);
  		setDuration(DEFAULT_DURATION);
  	}
  
  	private Particle generateParticle(int color, Random random) {
  		Particle particle = new Particle();
  		particle.color = color;
  		particle.radius = V;
  		if (random.nextFloat() < 0.2f) {
  			particle.baseRadius = V + ((X - V) * random.nextFloat());
  		} else {
  			particle.baseRadius = W + ((V - W) * random.nextFloat());
  		}
  		float nextFloat = random.nextFloat();
  		particle.top = mBound.height() * ((0.18f * random.nextFloat()) + 0.2f);
  		particle.top = nextFloat < 0.2f ? particle.top : particle.top + ((particle.top * 0.2f) * random.nextFloat());
  		particle.bottom = (mBound.height() * (random.nextFloat() - 0.5f)) * 1.8f;
  		float f = nextFloat < 0.2f
  				? particle.bottom
  				: nextFloat < 0.8f ? particle.bottom * 0.6f : particle.bottom * 0.3f;
  		particle.bottom = f;
  		particle.mag = 4.0f * particle.top / particle.bottom;
  		particle.neg = (-particle.mag) / particle.bottom;
  		f = mBound.centerX() + (Y * (random.nextFloat() - 0.5f));
  		particle.baseCx = f;
  		particle.cx = f;
  		f = mBound.centerY() + (Y * (random.nextFloat() - 0.5f));
  		particle.baseCy = f;
  		particle.cy = f;
  		particle.life = END_VALUE / 10 * random.nextFloat();
  		particle.overflow = 0.4f * random.nextFloat();
  		particle.alpha = 1f;
  		return particle;
  	}
  
  	public boolean draw(Canvas canvas) {
  		if (!isStarted()) {
  			return false;
  		}
  		for (Particle particle : mParticles) {
  			particle.advance((float) getAnimatedValue());
  			if (particle.alpha > 0f) {
  				mPaint.setColor(particle.color);
  				mPaint.setAlpha((int) (Color.alpha(particle.color) * particle.alpha));
  				canvas.drawCircle(particle.cx, particle.cy, particle.radius, mPaint);
  			}
  		}
  		mContainer.invalidate();
  		return true;
  	}
  
  	@Override
  	public void start() {
  		super.start();
  		mContainer.invalidate(mBound);
  	}
  
  	private class Particle {
  		float alpha;
  		int color;
  		float cx;
  		float cy;
  		float radius;
  		float baseCx;
  		float baseCy;
  		float baseRadius;
  		float top;
  		float bottom;
  		float mag;
  		float neg;
  		float life;
  		float overflow;
  
  		public void advance(float factor) {
  			float f = 0f;
  			float normalization = factor / END_VALUE;
  			if (normalization < life || normalization > 1f - overflow) {
  				alpha = 0f;
  				return;
  			}
  			normalization = (normalization - life) / (1f - life - overflow);
  			float f2 = normalization * END_VALUE;
  			if (normalization >= 0.7f) {
  				f = (normalization - 0.7f) / 0.3f;
  			}
  			alpha = 1f - f;
  			f = bottom * f2;
  			cx = baseCx + f;
  			cy = (float) (baseCy - this.neg * Math.pow(f, 2.0)) - f * mag;
  			radius = V + (baseRadius - V) * f2;
  		}
  	}
  }
  