/*
* Copyright (C) 2016 Bilibili
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.bilibili.magicasakura.utils;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.StateSet;
import android.util.TypedValue;
import android.util.Xml;
import com.wm.remusic.R;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
/**
* @author xyczero617@gmail.com
* @time 16/2/22
*/
public abstract class DrawableUtils {
protected abstract Drawable inflateDrawable(Context context, XmlPullParser parser, AttributeSet attrs) throws IOException, XmlPullParserException;
static Drawable createDrawable(Context context, int resId) {
if (resId <= 0) return null;
final TypedValue typedValue = new TypedValue();
final Resources res = context.getResources();
res.getValue(resId, typedValue, true);
Drawable dr = null;
if (typedValue.type >= TypedValue.TYPE_FIRST_COLOR_INT
&& typedValue.type <= TypedValue.TYPE_LAST_COLOR_INT) {
dr = new ColorDrawable(ThemeUtils.replaceColorById(context, resId));
} else {
try {
if (typedValue.string != null && typedValue.string.toString().endsWith("xml")) {
final XmlResourceParser rp = res.getXml(resId);
final AttributeSet attrs = Xml.asAttributeSet(rp);
int type;
while ((type = rp.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty loop
}
if (type != XmlPullParser.START_TAG) {
throw new XmlPullParserException("No start tag found");
}
dr = createFromXmlInner(context, rp, attrs);
rp.close();
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
}
return dr;
}
static Drawable createFromXmlInner(Context context, XmlPullParser parser, AttributeSet attrs) throws IOException, XmlPullParserException {
final DrawableUtils drawableUtils;
final String name = parser.getName();
switch (name) {
case "selector":
drawableUtils = new StateListDrawableUtils();
break;
case "shape":
drawableUtils = new GradientDrawableUtils();
break;
case "layer-list":
drawableUtils = new LayerDrawableUtils();
break;
default:
drawableUtils = null;
}
return drawableUtils == null ? null : drawableUtils.inflateDrawable(context, parser, attrs);
}
/**
* Extracts state_ attributes from an attribute set.
*
* @param attrs The attribute set.
* @return An array of state_ attributes.
*/
protected int[] extractStateSet(AttributeSet attrs) {
int j = 0;
final int numAttrs = attrs.getAttributeCount();
int[] states = new int[numAttrs];
for (int i = 0; i < numAttrs; i++) {
final int stateResId = attrs.getAttributeNameResource(i);
if (stateResId == 0) {
break;
} else if (stateResId == android.R.attr.drawable
|| stateResId == android.R.attr.id
|| stateResId == R.attr.drawableTint
|| stateResId == R.attr.drawableTintMode) {
// Ignore attributes from StateListDrawableItem and
// AnimatedStateListDrawableItem.
continue;
} else {
states[j++] = attrs.getAttributeBooleanValue(i, false)
? stateResId : -stateResId;
}
}
states = StateSet.trimStateSet(states, j);
return states;
}
static int getAttrTintColor(Context context, AttributeSet attrs, int attr, int defaultValue) {
final TypedArray a = obtainAttributes(context.getResources(), context.getTheme(), attrs, new int[]{attr});
final int tintColor = ThemeUtils.replaceColor(context, a.getColor(0, defaultValue));
a.recycle();
return tintColor;
}
static Drawable getAttrDrawable(Context context, AttributeSet attrs, int attr) {
final TypedArray a = obtainAttributes(context.getResources(), context.getTheme(), attrs, new int[]{attr});
final int resId = a.getResourceId(0, 0);
Drawable drawable = null;
if (resId != 0) {
drawable = createDrawable(context, resId);
if (drawable == null) {
drawable = a.getDrawable(0);
}
}
a.recycle();
return drawable;
}
static ColorFilter getAttrColorFilter(Context context, AttributeSet attrs, int tintAttr, int tintModeAttr) {
final int color = getAttrColor(context, attrs, tintAttr, Color.TRANSPARENT);
if (color == Color.TRANSPARENT) return null;
return new PorterDuffColorFilter(color, getTintMode(context, attrs, tintModeAttr));
}
static ColorStateList getTintColorList(Context context, AttributeSet attrs, int tintAttr) {
TypedArray a = obtainAttributes(context.getResources(), context.getTheme(), attrs, new int[]{tintAttr});
if (!a.hasValue(0)) {
a.recycle();
return null;
}
final ColorStateList cls = TintManager.get(context).getColorStateList(a.getResourceId(0, 0));
a.recycle();
return cls;
}
static PorterDuff.Mode getTintMode(Context context, AttributeSet attrs, int tintModeAttr) {
TypedArray a = obtainAttributes(context.getResources(), context.getTheme(), attrs, new int[]{tintModeAttr});
final int tintModeValue = a.getInt(0, 0);
a.recycle();
return parseTintMode(tintModeValue, PorterDuff.Mode.SRC_IN);
}
static int getAttrDimensionPixelSize(Context context, AttributeSet attrs, int attr) {
return getAttrDimensionPixelSize(context, attrs, attr, 0);
}
static int getAttrDimensionPixelSize(Context context, AttributeSet attrs, int attr, int defaultValue) {
TypedArray a = obtainAttributes(context.getResources(), context.getTheme(), attrs, new int[]{attr});
final int value = a.getDimensionPixelSize(0, defaultValue);
a.recycle();
return value;
}
static int getAttrColor(Context context, AttributeSet attrs, int attr, int defaultValue) {
TypedArray a = obtainAttributes(context.getResources(), context.getTheme(), attrs, new int[]{attr});
final int colorId = a.getResourceId(0, 0);
final int value = colorId != 0 ? ThemeUtils.replaceColorById(context, colorId) : ThemeUtils.replaceColor(context, a.getColor(0, defaultValue));
a.recycle();
return value;
}
static int getAttrDimensionPixelOffset(Context context, AttributeSet attrs, int attr) {
return getAttrDimensionPixelOffset(context, attrs, attr, 0);
}
static int getAttrDimensionPixelOffset(Context context, AttributeSet attrs, int attr, int defaultValue) {
TypedArray a = obtainAttributes(context.getResources(), context.getTheme(), attrs, new int[]{attr});
final int value = a.getDimensionPixelOffset(0, defaultValue);
a.recycle();
return value;
}
static float getAttrDimension(Context context, AttributeSet attrs, int attr) {
return getAttrDimension(context, attrs, attr, 0);
}
static float getAttrDimension(Context context, AttributeSet attrs, int attr, int defaultValue) {
TypedArray a = obtainAttributes(context.getResources(), context.getTheme(), attrs, new int[]{attr});
final float value = a.getDimension(0, defaultValue);
a.recycle();
return value;
}
static float getAttrFloat(Context context, AttributeSet attrs, int attr, float defaultValue) {
TypedArray a = obtainAttributes(context.getResources(), context.getTheme(), attrs, new int[]{attr});
final float alphaMod = a.getFloat(0, defaultValue);
a.recycle();
return alphaMod;
}
static int getAttrInt(Context context, AttributeSet attrs, int attr, int defaultValue) {
TypedArray a = obtainAttributes(context.getResources(), context.getTheme(), attrs, new int[]{attr});
final int value = a.getInt(0, defaultValue);
a.recycle();
return value;
}
static boolean getAttrBoolean(Context context, AttributeSet attrs, int attr, boolean defaultValue) {
TypedArray a = obtainAttributes(context.getResources(), context.getTheme(), attrs, new int[]{attr});
final boolean value = a.getBoolean(0, defaultValue);
a.recycle();
return value;
}
static boolean getAttrHasValue(Context context, AttributeSet attrs, int attr) {
TypedArray a = obtainAttributes(context.getResources(), context.getTheme(), attrs, new int[]{attr});
final boolean flag = a.hasValue(0);
a.recycle();
return flag;
}
static int getAttrResourceId(Context context, AttributeSet attrs, int attr, int defaultValue) {
TypedArray a = obtainAttributes(context.getResources(), context.getTheme(), attrs, new int[]{attr});
final int id = a.getResourceId(0, defaultValue);
a.recycle();
return id;
}
static TypedArray obtainAttributes(
Resources res, Resources.Theme theme, AttributeSet set, int[] attrs) {
if (theme == null) {
return res.obtainAttributes(set, attrs);
}
return theme.obtainStyledAttributes(set, attrs, 0, 0);
}
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 Build.VERSION.SDK_INT >= 11 ? PorterDuff.Mode.valueOf("ADD")
: defaultMode;
default:
return defaultMode;
}
}
}