package com.luciofm.droidcon.ifican.anim;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.os.Handler;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
import android.transition.Transition;
import android.transition.TransitionManager;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.BounceInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
/**
* Created by luciofm on 5/25/14.
*/
public class AnimUtils {
public static final int ANIM_MULTIPLIER = 1;
public static final int ANIM_DURATION = 300 * ANIM_MULTIPLIER;
public static Interpolator BOUNCE = new BounceInterpolator();
public static Interpolator OVERSHOOT = new OvershootInterpolator(2.8f);
public static Interpolator ANTICIPATE = new AnticipateInterpolator(2.8f);
public static Interpolator ACCELERATE = new AccelerateInterpolator();
public static Interpolator DECELERATE = new DecelerateInterpolator();
public static Interpolator ACCELDECEL = new AccelerateDecelerateInterpolator();
private AnimUtils() {
}
public static void shakeView(final View view) {
ObjectAnimator physX = ObjectAnimator.ofFloat(view, "translationX", -12f, 12f);
physX.setDuration(50);
physX.setRepeatCount(10);
physX.setRepeatMode(ObjectAnimator.RESTART);
physX.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationEnd(Animator animation) {
view.animate().translationX(0f).setDuration(10);
}
});
physX.start();
}
public static void beginDelayedTransition(ViewGroup container) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
TransitionManager.beginDelayedTransition(container);
}
public static void beginDelayedTransition(ViewGroup container, Transition set) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
TransitionManager.beginDelayedTransition(container, set);
}
public static Animator createXTransition(View view, boolean enter) {
ObjectAnimator x;
ObjectAnimator y;
if (enter) {
x = ObjectAnimator.ofFloat(view, "translationX", 1f, 0f);
y = ObjectAnimator.ofFloat(view, "translationY", 1f, 0f);
} else {
x = ObjectAnimator.ofFloat(view, "translationX", 0f, -1f);
y = ObjectAnimator.ofFloat(view, "translationY", 0f, -1f);
}
AnimatorSet set = new AnimatorSet();
set.playTogether(x, y);
return set;
}
/**
* This method of image pixelization utilizes the bitmap scaling operations built
* into the framework. By downscaling the bitmap and upscaling it back to its
* original size (while setting the filter flag to false), the same effect can be
* achieved with much better performance.
*/
public static BitmapDrawable builtInPixelization(Context context, float pixelizationFactor,
Bitmap bitmap) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int downScaleFactorWidth = (int) (pixelizationFactor * width);
downScaleFactorWidth = downScaleFactorWidth > 0 ? downScaleFactorWidth : 1;
int downScaleFactorHeight = (int) (pixelizationFactor * height);
downScaleFactorHeight = downScaleFactorHeight > 0 ? downScaleFactorHeight : 1;
int downScaledWidth = width / downScaleFactorWidth;
int downScaledHeight = height / downScaleFactorHeight;
Bitmap pixelatedBitmap = Bitmap.createScaledBitmap(bitmap, downScaledWidth,
downScaledHeight, false);
/* Bitmap's createScaledBitmap method has a filter parameter that can be set to either
* true or false in order to specify either bilinear filtering or point sampling
* respectively when the bitmap is scaled up or now.
*
* Similarly, a BitmapDrawable also has a flag to specify the same thing. When the
* BitmapDrawable is applied to an ImageView that has some scaleType, the filtering
* flag is taken into consideration. However, for optimization purposes, this flag was
* ignored in BitmapDrawables before Jelly Bean MR1.
*
* Here, it is important to note that prior to JBMR1, two bitmap scaling operations
* are required to achieve the pixelization effect. Otherwise, a BitmapDrawable
* can be created corresponding to the downscaled bitmap such that when it is
* upscaled to fit the ImageView, the upscaling operation is a lot faster since
* it uses internal optimizations to fit the ImageView.
* */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
BitmapDrawable bitmapDrawable = new BitmapDrawable(context.getResources(),
pixelatedBitmap);
bitmapDrawable.setFilterBitmap(false);
return bitmapDrawable;
} else {
Bitmap upscaled = Bitmap.createScaledBitmap(pixelatedBitmap, width, height, false);
return new BitmapDrawable(context.getResources(), upscaled);
}
}
public static final float DEFAULT_BLUR_RADIUS = 12f;
public static Bitmap fastblur(Context context, Bitmap sentBitmap) {
return fastblur(context, sentBitmap, DEFAULT_BLUR_RADIUS);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public static Bitmap fastblur(Context context, Bitmap sentBitmap, float radius) {
if (Build.VERSION.SDK_INT > 16 &&
(!Build.MODEL.contains("google_sdk")
&& !Build.MODEL.contains("Emulator")
&& !Build.MODEL.contains("Android SDK")
&& !Build.FINGERPRINT.contains("vbox86p"))) {
Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
final RenderScript rs = RenderScript.create(context);
final Allocation input = Allocation.createFromBitmap(rs, sentBitmap, Allocation.MipmapControl.MIPMAP_NONE,
Allocation.USAGE_SCRIPT);
final Allocation output = Allocation.createTyped(rs, input.getType());
final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setRadius(radius /* e.g. 3.f */);
script.setInput(input);
script.forEach(output);
output.copyTo(bitmap);
return bitmap;
}
radius *= 0.1;
return blurfast(sentBitmap, (int) radius);
}
static Bitmap blurfast(Bitmap bmp, int radius) {
try {
Bitmap bitmap = bmp.copy(bmp.getConfig(), true);
int w = bmp.getWidth();
int h = bmp.getHeight();
int[] pix = new int[w * h];
bmp.getPixels(pix, 0, w, 0, 0, w, h);
for(int r = radius; r >= 1; r /= 2) {
for(int i = r; i < h - r; i++) {
for(int j = r; j < w - r; j++) {
int tl = pix[(i - r) * w + j - r];
int tr = pix[(i - r) * w + j + r];
int tc = pix[(i - r) * w + j];
int bl = pix[(i + r) * w + j - r];
int br = pix[(i + r) * w + j + r];
int bc = pix[(i + r) * w + j];
int cl = pix[i * w + j - r];
int cr = pix[i * w + j + r];
pix[(i * w) + j] = 0xFF000000 |
(((tl & 0xFF) + (tr & 0xFF) + (tc & 0xFF) + (bl & 0xFF) + (br & 0xFF) + (bc & 0xFF) + (cl & 0xFF) + (cr & 0xFF)) >> 3) & 0xFF |
(((tl & 0xFF00) + (tr & 0xFF00) + (tc & 0xFF00) + (bl & 0xFF00) + (br & 0xFF00) + (bc & 0xFF00) + (cl & 0xFF00) + (cr & 0xFF00)) >> 3) & 0xFF00 |
(((tl & 0xFF0000) + (tr & 0xFF0000) + (tc & 0xFF0000) + (bl & 0xFF0000) + (br & 0xFF0000) + (bc & 0xFF0000) + (cl & 0xFF0000) + (cr & 0xFF0000)) >> 3) & 0xFF0000;
}
}
}
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
return bitmap;
}catch (Exception e) {
return bmp;
}
}
public static void popOutViewDelayed(final View view, long delay) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (view == null)
return;
view.setVisibility(View.VISIBLE);
view.setScaleY(0f);
view.setScaleX(0f);
view.animate().scaleX(1f).scaleY(1f).setInterpolator(OVERSHOOT).setDuration(ANIM_DURATION);
}
}, delay);
}
public static void animateHeartBeat(View view) {
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1.1f);
scaleX.setInterpolator(ANTICIPATE);
scaleX.setRepeatCount(1);
scaleX.setRepeatMode(ValueAnimator.REVERSE);
scaleX.setDuration((long) (200));
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1.1f);
scaleY.setInterpolator(ANTICIPATE);
scaleY.setRepeatCount(1);
scaleY.setRepeatMode(ValueAnimator.REVERSE);
scaleY.setDuration((long) (200));
AnimatorSet set1 = new AnimatorSet();
set1.playTogether(scaleX, scaleY);
AnimatorSet set2 = new AnimatorSet();
set2.playTogether(scaleX, scaleY);
AnimatorSet animSet = new AnimatorSet();
animSet.playSequentially(set1, set2);
animSet.start();
}
public static View.OnTouchListener setupResizeTouchListener(View v) {
View.OnTouchListener touchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
v.animate().setInterpolator(OVERSHOOT)
.scaleX(.85f).scaleY(.85f)
.setStartDelay(0).setDuration(ANIM_DURATION)
.setListener(null);
} else if (event.getAction() == MotionEvent.ACTION_UP ||
event.getAction() == MotionEvent.ACTION_CANCEL ||
event.getAction() == MotionEvent.ACTION_OUTSIDE) {
v.animate().setInterpolator(OVERSHOOT)
.scaleX(1f).scaleY(1f)
.setStartDelay(0).setDuration(ANIM_DURATION)
.setListener(null);
}
return false;
}
};
v.setOnTouchListener(touchListener);
return touchListener;
}
}