package codetail.graphics.drawables; import android.annotation.TargetApi; import android.content.res.ColorStateList; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.graphics.drawable.InsetDrawable; import android.os.Build; import android.support.v4.util.LruCache; public class DrawableHelper { final static boolean COMPAT = Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP; final static ColorFilterLruCache COLOR_FILTER_CACHE = new ColorFilterLruCache(6); /** * Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode * attribute's enum value. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static PorterDuff.Mode parseTintMode(int value, PorterDuff.Mode defaultMode) { switch (value) { case 3: return PorterDuff.Mode.SRC_OVER; case 5: return PorterDuff.Mode.SRC_IN; case 9: return PorterDuff.Mode.SRC_ATOP; case 14: return PorterDuff.Mode.MULTIPLY; case 15: return PorterDuff.Mode.SCREEN; case 16: return COMPAT ? defaultMode : PorterDuff.Mode.ADD; default: return defaultMode; } } public static void setTint(Drawable drawable, int color){ if(Build.VERSION.SDK_INT >= 21){ drawable.setTint(color); }else{ drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); } } /** * Ensures the tint filter is consistent with the current tint color and * mode. */ private static PorterDuffColorFilter updateTintFilter(ColorStateList tint, PorterDuff.Mode tintMode, int[] drawableState) { if (tint == null || tintMode == null) { return null; } final int color = tint.getColorForState(drawableState, Color.TRANSPARENT); PorterDuffColorFilter filter = COLOR_FILTER_CACHE.get(color, tintMode); if(filter == null) { filter = new PorterDuffColorFilter(color, tintMode); COLOR_FILTER_CACHE.put(color, tintMode, filter); } return filter; } static void updateTintFilter(Drawable who, ColorStateList tint, PorterDuff.Mode tintMode, int[] drawableState){ PorterDuffColorFilter filter = updateTintFilter(tint, tintMode, drawableState); who.setColorFilter(filter); } public static class DrawableCompat extends InsetDrawable{ Drawable mWrapped; ColorStateList mTintList; PorterDuff.Mode mTintMode = PorterDuff.Mode.SRC_ATOP; public static DrawableCompat wrap(Drawable drawable){ return new DrawableCompat(drawable); } private DrawableCompat(Drawable drawable) { super(drawable, 0); mWrapped = drawable; } @Override public boolean setState(int[] stateSet) { if(COMPAT){ updateTintFilter(this, mTintList, mTintMode, stateSet); } return super.setState(stateSet); } @Override @TargetApi(Build.VERSION_CODES.LOLLIPOP) public void setTintList(ColorStateList tint) { if(COMPAT){ mTintList = tint; updateTintFilter(this, mTintList, mTintMode, getState()); return; } super.setTintList(tint); } @Override @TargetApi(Build.VERSION_CODES.LOLLIPOP) public void setTintMode(PorterDuff.Mode tintMode) { if(COMPAT){ mTintMode = tintMode; updateTintFilter(this, mTintList, mTintMode, getState()); return; } super.setTintMode(tintMode); } @Override @TargetApi(Build.VERSION_CODES.LOLLIPOP) public void setTint(int tint) { if(COMPAT){ setTintList(ColorStateList.valueOf(tint)); return; } super.setTint(tint); } @Override public Drawable getDrawable() { return mWrapped; } @Override public DrawableCompat mutate() { return (DrawableCompat) super.mutate(); } } private static class ColorFilterLruCache extends LruCache<Integer, PorterDuffColorFilter> { public ColorFilterLruCache(int maxSize) { super(maxSize); } PorterDuffColorFilter get(int color, PorterDuff.Mode mode) { return get(generateCacheKey(color, mode)); } PorterDuffColorFilter put(int color, PorterDuff.Mode mode, PorterDuffColorFilter filter) { return put(generateCacheKey(color, mode), filter); } private static int generateCacheKey(int color, PorterDuff.Mode mode) { int hashCode = 1; hashCode = 31 * hashCode + color; hashCode = 31 * hashCode + mode.hashCode(); return hashCode; } } }