package carbon.animation;
import android.animation.ValueAnimator;
import android.content.res.ColorStateList;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.StateSet;
import android.view.animation.AccelerateDecelerateInterpolator;
import java.lang.reflect.Field;
import java.util.Arrays;
import carbon.internal.ArgbEvaluator;
public class AnimatedColorStateList extends ColorStateList {
private final int[][] states;
private int[] currentState = null;
private ValueAnimator colorAnimation = null;
private int animatedColor;
public static AnimatedColorStateList fromList(ColorStateList list, ValueAnimator.AnimatorUpdateListener listener) {
int[][] mStateSpecs; // must be parallel to mColors
int[] mColors; // must be parallel to mStateSpecs
int mDefaultColor;
try {
Field mStateSpecsField = ColorStateList.class.getDeclaredField("mStateSpecs");
mStateSpecsField.setAccessible(true);
mStateSpecs = (int[][]) mStateSpecsField.get(list);
Field mColorsField = ColorStateList.class.getDeclaredField("mColors");
mColorsField.setAccessible(true);
mColors = (int[]) mColorsField.get(list);
Field mDefaultColorField = ColorStateList.class.getDeclaredField("mDefaultColor");
mDefaultColorField.setAccessible(true);
mDefaultColor = (int) mDefaultColorField.get(list);
AnimatedColorStateList animatedColorStateList = new AnimatedColorStateList(mStateSpecs, mColors, listener);
mDefaultColorField.set(animatedColorStateList, mDefaultColor);
return animatedColorStateList;
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
public AnimatedColorStateList(int[][] states, int[] colors, final ValueAnimator.AnimatorUpdateListener listener) {
super(states, colors);
this.states = states;
colorAnimation = ValueAnimator.ofInt(0, 0);
colorAnimation.setEvaluator(new ArgbEvaluator());
colorAnimation.setDuration(200);
colorAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
colorAnimation.addUpdateListener(animation -> {
synchronized (AnimatedColorStateList.this) {
animatedColor = (int) animation.getAnimatedValue();
listener.onAnimationUpdate(animation);
}
});
}
@Override
public int getColorForState(int[] stateSet, int defaultColor) {
synchronized (AnimatedColorStateList.this) {
if (Arrays.equals(stateSet, currentState)) {
return animatedColor;
}
}
return super.getColorForState(stateSet, defaultColor);
}
public void setState(int[] newState) {
if (Arrays.equals(newState, currentState))
return;
if (currentState != null)
cancel();
for (final int[] state : states) {
if (StateSet.stateSetMatches(state, newState)) {
int firstColor = super.getColorForState(currentState, getDefaultColor());
int secondColor = super.getColorForState(newState, getDefaultColor());
colorAnimation.setIntValues(firstColor, secondColor);
currentState = newState;
animatedColor = firstColor;
colorAnimation.start();
return;
}
}
currentState = newState;
}
private void cancel() {
colorAnimation.cancel();
}
public void jumpToCurrentState() {
colorAnimation.end();
}
public static final Parcelable.Creator<AnimatedColorStateList> CREATOR =
new Parcelable.Creator<AnimatedColorStateList>() {
@Override
public AnimatedColorStateList[] newArray(int size) {
return new AnimatedColorStateList[size];
}
@Override
public AnimatedColorStateList createFromParcel(Parcel source) {
final int N = source.readInt();
final int[][] stateSpecs = new int[N][];
for (int i = 0; i < N; i++) {
stateSpecs[i] = source.createIntArray();
}
final int[] colors = source.createIntArray();
return AnimatedColorStateList.fromList(new ColorStateList(stateSpecs, colors), null);
}
};
}