Merge "Allow use of theme attributes in color state lists"
This commit is contained in:
committed by
Android (Google) Code Review
commit
304ea5aac7
@@ -2407,6 +2407,7 @@ package android {
|
||||
field public static final int Widget_Material_Button_Borderless = 16974425; // 0x1030259
|
||||
field public static final int Widget_Material_Button_Borderless_Colored = 16974426; // 0x103025a
|
||||
field public static final int Widget_Material_Button_Borderless_Small = 16974427; // 0x103025b
|
||||
field public static final int Widget_Material_Button_Colored = 16974547; // 0x10302d3
|
||||
field public static final int Widget_Material_Button_Inset = 16974428; // 0x103025c
|
||||
field public static final int Widget_Material_Button_Small = 16974429; // 0x103025d
|
||||
field public static final int Widget_Material_Button_Toggle = 16974430; // 0x103025e
|
||||
@@ -7148,6 +7149,8 @@ package android.content {
|
||||
method public abstract java.io.File getCacheDir();
|
||||
method public abstract java.lang.ClassLoader getClassLoader();
|
||||
method public abstract java.io.File getCodeCacheDir();
|
||||
method public final int getColor(int);
|
||||
method public final android.content.res.ColorStateList getColorStateList(int);
|
||||
method public abstract android.content.ContentResolver getContentResolver();
|
||||
method public abstract java.io.File getDatabasePath(java.lang.String);
|
||||
method public abstract java.io.File getDir(java.lang.String, int);
|
||||
@@ -9076,7 +9079,10 @@ package android.content.res {
|
||||
|
||||
public class ColorStateList implements android.os.Parcelable {
|
||||
ctor public ColorStateList(int[][], int[]);
|
||||
method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
|
||||
method public void applyTheme(android.content.res.Resources.Theme);
|
||||
method public boolean canApplyTheme();
|
||||
method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
|
||||
method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
|
||||
method public int describeContents();
|
||||
method public int getColorForState(int[], int);
|
||||
method public int getDefaultColor();
|
||||
@@ -9206,8 +9212,10 @@ package android.content.res {
|
||||
method public android.content.res.XmlResourceParser getAnimation(int) throws android.content.res.Resources.NotFoundException;
|
||||
method public final android.content.res.AssetManager getAssets();
|
||||
method public boolean getBoolean(int) throws android.content.res.Resources.NotFoundException;
|
||||
method public int getColor(int) throws android.content.res.Resources.NotFoundException;
|
||||
method public android.content.res.ColorStateList getColorStateList(int) throws android.content.res.Resources.NotFoundException;
|
||||
method public deprecated int getColor(int) throws android.content.res.Resources.NotFoundException;
|
||||
method public int getColor(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
|
||||
method public deprecated android.content.res.ColorStateList getColorStateList(int) throws android.content.res.Resources.NotFoundException;
|
||||
method public android.content.res.ColorStateList getColorStateList(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
|
||||
method public android.content.res.Configuration getConfiguration();
|
||||
method public float getDimension(int) throws android.content.res.Resources.NotFoundException;
|
||||
method public int getDimensionPixelOffset(int) throws android.content.res.Resources.NotFoundException;
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.annotation.SystemApi;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
@@ -392,18 +393,55 @@ public abstract class Context {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a drawable object associated with a particular resource ID and
|
||||
* Returns a color associated with a particular resource ID and styled for
|
||||
* the current theme.
|
||||
*
|
||||
* @param id The desired resource identifier, as generated by the aapt
|
||||
* tool. This integer encodes the package, type, and resource
|
||||
* entry. The value 0 is an invalid identifier.
|
||||
* @return A single color value in the form 0xAARRGGBB.
|
||||
* @throws android.content.res.Resources.NotFoundException if the given ID
|
||||
* does not exist.
|
||||
*/
|
||||
@Nullable
|
||||
public final int getColor(int id) {
|
||||
return getResources().getColor(id, getTheme());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a drawable object associated with a particular resource ID and
|
||||
* styled for the current theme.
|
||||
*
|
||||
* @param id The desired resource identifier, as generated by the aapt
|
||||
* tool. This integer encodes the package, type, and resource
|
||||
* entry. The value 0 is an invalid identifier.
|
||||
* @return Drawable An object that can be used to draw this resource.
|
||||
* @return An object that can be used to draw this resource, or
|
||||
* {@code null} if the resource could not be resolved.
|
||||
* @throws android.content.res.Resources.NotFoundException if the given ID
|
||||
* does not exist.
|
||||
*/
|
||||
@Nullable
|
||||
public final Drawable getDrawable(int id) {
|
||||
return getResources().getDrawable(id, getTheme());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a color state list associated with a particular resource ID and
|
||||
* styled for the current theme.
|
||||
*
|
||||
* @param id The desired resource identifier, as generated by the aapt
|
||||
* tool. This integer encodes the package, type, and resource
|
||||
* entry. The value 0 is an invalid identifier.
|
||||
* @return A color state list, or {@code null} if the resource could not be
|
||||
* resolved.
|
||||
* @throws android.content.res.Resources.NotFoundException if the given ID
|
||||
* does not exist.
|
||||
*/
|
||||
@Nullable
|
||||
public final ColorStateList getColorStateList(int id) {
|
||||
return getResources().getColorStateList(id, getTheme());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the base theme for this context. Note that this should be called
|
||||
* before any views are instantiated in the Context (for example before
|
||||
|
||||
@@ -16,8 +16,12 @@
|
||||
|
||||
package android.content.res;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.res.Resources.Theme;
|
||||
import android.graphics.Color;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.GrowingArrayUtils;
|
||||
|
||||
@@ -25,6 +29,7 @@ import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.MathUtils;
|
||||
import android.util.SparseArray;
|
||||
import android.util.StateSet;
|
||||
@@ -64,15 +69,23 @@ import java.util.Arrays;
|
||||
* List Resource</a>.</p>
|
||||
*/
|
||||
public class ColorStateList implements Parcelable {
|
||||
private int[][] mStateSpecs; // must be parallel to mColors
|
||||
private int[] mColors; // must be parallel to mStateSpecs
|
||||
private int mDefaultColor = 0xffff0000;
|
||||
|
||||
private static final String TAG = "ColorStateList";
|
||||
private static final int DEFAULT_COLOR = Color.RED;
|
||||
private static final int[][] EMPTY = new int[][] { new int[0] };
|
||||
private static final SparseArray<WeakReference<ColorStateList>> sCache =
|
||||
new SparseArray<WeakReference<ColorStateList>>();
|
||||
|
||||
private ColorStateList() { }
|
||||
private int[][] mThemeAttrs;
|
||||
private int mChangingConfigurations;
|
||||
|
||||
private int[][] mStateSpecs;
|
||||
private int[] mColors;
|
||||
private int mDefaultColor;
|
||||
private boolean mIsOpaque;
|
||||
|
||||
private ColorStateList() {
|
||||
// Not publicly instantiable.
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ColorStateList that returns the specified mapping from
|
||||
@@ -82,53 +95,102 @@ public class ColorStateList implements Parcelable {
|
||||
mStateSpecs = states;
|
||||
mColors = colors;
|
||||
|
||||
if (states.length > 0) {
|
||||
mDefaultColor = colors[0];
|
||||
|
||||
for (int i = 0; i < states.length; i++) {
|
||||
if (states[i].length == 0) {
|
||||
mDefaultColor = colors[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
onColorsChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or retrieves a ColorStateList that always returns a single color.
|
||||
* @return A ColorStateList containing a single color.
|
||||
*/
|
||||
@NonNull
|
||||
public static ColorStateList valueOf(int color) {
|
||||
// TODO: should we collect these eventually?
|
||||
synchronized (sCache) {
|
||||
final WeakReference<ColorStateList> ref = sCache.get(color);
|
||||
final int index = sCache.indexOfKey(color);
|
||||
if (index >= 0) {
|
||||
final ColorStateList cached = sCache.valueAt(index).get();
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
ColorStateList csl = ref != null ? ref.get() : null;
|
||||
if (csl != null) {
|
||||
return csl;
|
||||
// Prune missing entry.
|
||||
sCache.removeAt(index);
|
||||
}
|
||||
|
||||
csl = new ColorStateList(EMPTY, new int[] { color });
|
||||
// Prune the cache before adding new items.
|
||||
final int N = sCache.size();
|
||||
for (int i = N - 1; i >= 0; i--) {
|
||||
if (sCache.valueAt(i).get() == null) {
|
||||
sCache.removeAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
final ColorStateList csl = new ColorStateList(EMPTY, new int[] { color });
|
||||
sCache.put(color, new WeakReference<ColorStateList>(csl));
|
||||
return csl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ColorStateList from an XML document, given a set of {@link Resources}.
|
||||
* Creates a ColorStateList with the same properties as another
|
||||
* ColorStateList.
|
||||
* <p>
|
||||
* The properties of the new ColorStateList can be modified without
|
||||
* affecting the source ColorStateList.
|
||||
*
|
||||
* @param orig the source color state list
|
||||
*/
|
||||
private ColorStateList(ColorStateList orig) {
|
||||
if (orig != null) {
|
||||
mStateSpecs = orig.mStateSpecs;
|
||||
mDefaultColor = orig.mDefaultColor;
|
||||
mIsOpaque = orig.mIsOpaque;
|
||||
|
||||
// Deep copy, this may change due to theming.
|
||||
mColors = orig.mColors.clone();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ColorStateList from an XML document.
|
||||
*
|
||||
* @param r Resources against which the ColorStateList should be inflated.
|
||||
* @param parser Parser for the XML document defining the ColorStateList.
|
||||
* @return A new color state list.
|
||||
*
|
||||
* @deprecated Use #createFromXml(Resources, XmlPullParser parser, Theme)
|
||||
*/
|
||||
@NonNull
|
||||
@Deprecated
|
||||
public static ColorStateList createFromXml(Resources r, XmlPullParser parser)
|
||||
throws XmlPullParserException, IOException {
|
||||
return createFromXml(r, parser, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ColorStateList from an XML document using given a set of
|
||||
* {@link Resources} and a {@link Theme}.
|
||||
*
|
||||
* @param r Resources against which the ColorStateList should be inflated.
|
||||
* @param parser Parser for the XML document defining the ColorStateList.
|
||||
* @param theme Optional theme to apply to the color state list, may be
|
||||
* {@code null}.
|
||||
* @return A new color state list.
|
||||
*/
|
||||
@NonNull
|
||||
public static ColorStateList createFromXml(@NonNull Resources r, @NonNull XmlPullParser parser,
|
||||
@Nullable Theme theme) throws XmlPullParserException, IOException {
|
||||
final AttributeSet attrs = Xml.asAttributeSet(parser);
|
||||
|
||||
int type;
|
||||
while ((type=parser.next()) != XmlPullParser.START_TAG
|
||||
while ((type = parser.next()) != XmlPullParser.START_TAG
|
||||
&& type != XmlPullParser.END_DOCUMENT) {
|
||||
// Seek parser to start tag.
|
||||
}
|
||||
|
||||
if (type != XmlPullParser.START_TAG) {
|
||||
throw new XmlPullParserException("No start tag found");
|
||||
}
|
||||
|
||||
return createFromXmlInner(r, parser, attrs);
|
||||
return createFromXmlInner(r, parser, attrs, theme);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,28 +198,31 @@ public class ColorStateList implements Parcelable {
|
||||
* tag in an XML document, tries to create a ColorStateList from that tag.
|
||||
*
|
||||
* @throws XmlPullParserException if the current tag is not <selector>
|
||||
* @return A color state list for the current tag.
|
||||
* @return A new color state list for the current tag.
|
||||
*/
|
||||
private static ColorStateList createFromXmlInner(Resources r, XmlPullParser parser,
|
||||
AttributeSet attrs) throws XmlPullParserException, IOException {
|
||||
final ColorStateList colorStateList;
|
||||
@NonNull
|
||||
private static ColorStateList createFromXmlInner(@NonNull Resources r,
|
||||
@NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
|
||||
throws XmlPullParserException, IOException {
|
||||
final String name = parser.getName();
|
||||
if (name.equals("selector")) {
|
||||
colorStateList = new ColorStateList();
|
||||
} else {
|
||||
if (!name.equals("selector")) {
|
||||
throw new XmlPullParserException(
|
||||
parser.getPositionDescription() + ": invalid drawable tag " + name);
|
||||
parser.getPositionDescription() + ": invalid color state list tag " + name);
|
||||
}
|
||||
|
||||
colorStateList.inflate(r, parser, attrs);
|
||||
final ColorStateList colorStateList = new ColorStateList();
|
||||
colorStateList.inflate(r, parser, attrs, theme);
|
||||
return colorStateList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ColorStateList that has the same states and
|
||||
* colors as this one but where each color has the specified alpha value
|
||||
* (0-255).
|
||||
* Creates a new ColorStateList that has the same states and colors as this
|
||||
* one but where each color has the specified alpha value (0-255).
|
||||
*
|
||||
* @param alpha The new alpha channel value (0-255).
|
||||
* @return A new color state list.
|
||||
*/
|
||||
@NonNull
|
||||
public ColorStateList withAlpha(int alpha) {
|
||||
final int[] colors = new int[mColors.length];
|
||||
final int len = colors.length;
|
||||
@@ -171,88 +236,154 @@ public class ColorStateList implements Parcelable {
|
||||
/**
|
||||
* Fill in this object based on the contents of an XML "selector" element.
|
||||
*/
|
||||
private void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
|
||||
private void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
|
||||
@NonNull AttributeSet attrs, @Nullable Theme theme)
|
||||
throws XmlPullParserException, IOException {
|
||||
int type;
|
||||
|
||||
final int innerDepth = parser.getDepth()+1;
|
||||
int depth;
|
||||
int type;
|
||||
|
||||
int changingConfigurations = 0;
|
||||
int defaultColor = DEFAULT_COLOR;
|
||||
|
||||
boolean hasUnresolvedAttrs = false;
|
||||
|
||||
int[][] stateSpecList = ArrayUtils.newUnpaddedArray(int[].class, 20);
|
||||
int[][] themeAttrsList = new int[stateSpecList.length][];
|
||||
int[] colorList = new int[stateSpecList.length];
|
||||
int listSize = 0;
|
||||
|
||||
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
|
||||
&& ((depth=parser.getDepth()) >= innerDepth
|
||||
|| type != XmlPullParser.END_TAG)) {
|
||||
if (type != XmlPullParser.START_TAG) {
|
||||
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
|
||||
&& ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
|
||||
if (type != XmlPullParser.START_TAG || depth > innerDepth
|
||||
|| !parser.getName().equals("item")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (depth > innerDepth || !parser.getName().equals("item")) {
|
||||
continue;
|
||||
}
|
||||
final TypedArray a = Resources.obtainAttributes(r, theme, attrs,
|
||||
R.styleable.ColorStateListItem);
|
||||
final int[] themeAttrs = a.extractThemeAttrs();
|
||||
final int baseColor = a.getColor(R.styleable.ColorStateListItem_color, 0);
|
||||
final float alphaMod = a.getFloat(R.styleable.ColorStateListItem_alpha, 1.0f);
|
||||
|
||||
int alphaRes = 0;
|
||||
float alpha = 1.0f;
|
||||
int colorRes = 0;
|
||||
int color = 0xffff0000;
|
||||
boolean haveColor = false;
|
||||
changingConfigurations |= a.getChangingConfigurations();
|
||||
|
||||
int i;
|
||||
a.recycle();
|
||||
|
||||
// Parse all unrecognized attributes as state specifiers.
|
||||
int j = 0;
|
||||
final int numAttrs = attrs.getAttributeCount();
|
||||
int[] stateSpec = new int[numAttrs];
|
||||
for (i = 0; i < numAttrs; i++) {
|
||||
for (int i = 0; i < numAttrs; i++) {
|
||||
final int stateResId = attrs.getAttributeNameResource(i);
|
||||
if (stateResId == 0) break;
|
||||
if (stateResId == com.android.internal.R.attr.alpha) {
|
||||
alphaRes = attrs.getAttributeResourceValue(i, 0);
|
||||
if (alphaRes == 0) {
|
||||
alpha = attrs.getAttributeFloatValue(i, 1.0f);
|
||||
}
|
||||
} else if (stateResId == com.android.internal.R.attr.color) {
|
||||
colorRes = attrs.getAttributeResourceValue(i, 0);
|
||||
if (colorRes == 0) {
|
||||
color = attrs.getAttributeIntValue(i, color);
|
||||
haveColor = true;
|
||||
}
|
||||
} else {
|
||||
stateSpec[j++] = attrs.getAttributeBooleanValue(i, false)
|
||||
? stateResId : -stateResId;
|
||||
switch (stateResId) {
|
||||
case R.attr.color:
|
||||
case R.attr.alpha:
|
||||
// Recognized attribute, ignore.
|
||||
break;
|
||||
default:
|
||||
stateSpec[j++] = attrs.getAttributeBooleanValue(i, false)
|
||||
? stateResId : -stateResId;
|
||||
}
|
||||
}
|
||||
stateSpec = StateSet.trimStateSet(stateSpec, j);
|
||||
|
||||
if (colorRes != 0) {
|
||||
color = r.getColor(colorRes);
|
||||
} else if (!haveColor) {
|
||||
throw new XmlPullParserException(
|
||||
parser.getPositionDescription()
|
||||
+ ": <item> tag requires a 'android:color' attribute.");
|
||||
}
|
||||
|
||||
if (alphaRes != 0) {
|
||||
alpha = r.getFloat(alphaRes);
|
||||
}
|
||||
|
||||
// Apply alpha modulation.
|
||||
final int alphaMod = MathUtils.constrain((int) (Color.alpha(color) * alpha), 0, 255);
|
||||
color = (color & 0xFFFFFF) | (alphaMod << 24);
|
||||
|
||||
final int color = modulateColorAlpha(baseColor, alphaMod);
|
||||
if (listSize == 0 || stateSpec.length == 0) {
|
||||
mDefaultColor = color;
|
||||
defaultColor = color;
|
||||
}
|
||||
|
||||
if (themeAttrs != null) {
|
||||
hasUnresolvedAttrs = true;
|
||||
}
|
||||
|
||||
colorList = GrowingArrayUtils.append(colorList, listSize, color);
|
||||
themeAttrsList = GrowingArrayUtils.append(themeAttrsList, listSize, themeAttrs);
|
||||
stateSpecList = GrowingArrayUtils.append(stateSpecList, listSize, stateSpec);
|
||||
listSize++;
|
||||
}
|
||||
|
||||
mChangingConfigurations = changingConfigurations;
|
||||
mDefaultColor = defaultColor;
|
||||
|
||||
if (hasUnresolvedAttrs) {
|
||||
mThemeAttrs = new int[listSize][];
|
||||
System.arraycopy(themeAttrsList, 0, mThemeAttrs, 0, listSize);
|
||||
} else {
|
||||
mThemeAttrs = null;
|
||||
}
|
||||
|
||||
mColors = new int[listSize];
|
||||
mStateSpecs = new int[listSize][];
|
||||
System.arraycopy(colorList, 0, mColors, 0, listSize);
|
||||
System.arraycopy(stateSpecList, 0, mStateSpecs, 0, listSize);
|
||||
|
||||
onColorsChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a theme can be applied to this color state list, which
|
||||
* usually indicates that the color state list has unresolved theme
|
||||
* attributes.
|
||||
*
|
||||
* @return whether a theme can be applied to this color state list
|
||||
*/
|
||||
public boolean canApplyTheme() {
|
||||
return mThemeAttrs != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a theme to this color state list.
|
||||
*
|
||||
* @param t the theme to apply
|
||||
*/
|
||||
public void applyTheme(Theme t) {
|
||||
if (mThemeAttrs == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasUnresolvedAttrs = false;
|
||||
|
||||
final int[][] themeAttrsList = mThemeAttrs;
|
||||
final int N = themeAttrsList.length;
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (themeAttrsList[i] != null) {
|
||||
final TypedArray a = t.resolveAttributes(themeAttrsList[i],
|
||||
R.styleable.ColorStateListItem);
|
||||
final int baseColor = a.getColor(
|
||||
R.styleable.ColorStateListItem_color, mColors[i]);
|
||||
final float alphaMod = a.getFloat(
|
||||
R.styleable.ColorStateListItem_alpha, 1.0f);
|
||||
|
||||
mColors[i] = modulateColorAlpha(baseColor, alphaMod);
|
||||
mChangingConfigurations |= a.getChangingConfigurations();
|
||||
|
||||
themeAttrsList[i] = a.extractThemeAttrs(themeAttrsList[i]);
|
||||
if (themeAttrsList[i] != null) {
|
||||
hasUnresolvedAttrs = true;
|
||||
}
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasUnresolvedAttrs) {
|
||||
mThemeAttrs = null;
|
||||
}
|
||||
|
||||
onColorsChanged();
|
||||
}
|
||||
|
||||
private int modulateColorAlpha(int baseColor, float alphaMod) {
|
||||
if (alphaMod == 1.0f) {
|
||||
return baseColor;
|
||||
}
|
||||
|
||||
final int baseAlpha = Color.alpha(baseColor);
|
||||
final int alpha = MathUtils.constrain((int) (baseAlpha * alphaMod + 0.5f), 0, 255);
|
||||
final int color = (baseColor & 0xFFFFFF) | (alpha << 24);
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -275,28 +406,24 @@ public class ColorStateList implements Parcelable {
|
||||
* @return True if this color state list is opaque.
|
||||
*/
|
||||
public boolean isOpaque() {
|
||||
final int n = mColors.length;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (Color.alpha(mColors[i]) != 0xFF) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return mIsOpaque;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the color associated with the given set of {@link android.view.View} states.
|
||||
* Return the color associated with the given set of
|
||||
* {@link android.view.View} states.
|
||||
*
|
||||
* @param stateSet an array of {@link android.view.View} states
|
||||
* @param defaultColor the color to return if there's not state spec in this
|
||||
* {@link ColorStateList} that matches the stateSet.
|
||||
* @param defaultColor the color to return if there's no matching state
|
||||
* spec in this {@link ColorStateList} that matches the
|
||||
* stateSet.
|
||||
*
|
||||
* @return the color associated with that set of states in this {@link ColorStateList}.
|
||||
*/
|
||||
public int getColorForState(int[] stateSet, int defaultColor) {
|
||||
public int getColorForState(@Nullable int[] stateSet, int defaultColor) {
|
||||
final int setLength = mStateSpecs.length;
|
||||
for (int i = 0; i < setLength; i++) {
|
||||
int[] stateSpec = mStateSpecs[i];
|
||||
final int[] stateSpec = mStateSpecs[i];
|
||||
if (StateSet.stateSetMatches(stateSpec, stateSet)) {
|
||||
return mColors[i];
|
||||
}
|
||||
@@ -314,7 +441,9 @@ public class ColorStateList implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the states in this {@link ColorStateList}.
|
||||
* Return the states in this {@link ColorStateList}. The returned array
|
||||
* should not be modified.
|
||||
*
|
||||
* @return the states in this {@link ColorStateList}
|
||||
* @hide
|
||||
*/
|
||||
@@ -323,7 +452,9 @@ public class ColorStateList implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the colors in this {@link ColorStateList}.
|
||||
* Return the colors in this {@link ColorStateList}. The returned array
|
||||
* should not be modified.
|
||||
*
|
||||
* @return the colors in this {@link ColorStateList}
|
||||
* @hide
|
||||
*/
|
||||
@@ -374,11 +505,81 @@ public class ColorStateList implements Parcelable {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ColorStateList{" +
|
||||
"mThemeAttrs=" + Arrays.deepToString(mThemeAttrs) +
|
||||
"mChangingConfigurations=" + mChangingConfigurations +
|
||||
"mStateSpecs=" + Arrays.deepToString(mStateSpecs) +
|
||||
"mColors=" + Arrays.toString(mColors) +
|
||||
"mDefaultColor=" + mDefaultColor + '}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the default color and opacity.
|
||||
*/
|
||||
private void onColorsChanged() {
|
||||
int defaultColor = DEFAULT_COLOR;
|
||||
boolean isOpaque = true;
|
||||
|
||||
final int[][] states = mStateSpecs;
|
||||
final int[] colors = mColors;
|
||||
final int N = states.length;
|
||||
if (N > 0) {
|
||||
defaultColor = colors[0];
|
||||
|
||||
for (int i = N - 1; i > 0; i--) {
|
||||
if (states[i].length == 0) {
|
||||
defaultColor = colors[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (Color.alpha(colors[i]) != 0xFF) {
|
||||
isOpaque = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mDefaultColor = defaultColor;
|
||||
mIsOpaque = isOpaque;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A factory that can create new instances of this ColorStateList.
|
||||
*/
|
||||
ColorStateListFactory getFactory() {
|
||||
return new ColorStateListFactory(this);
|
||||
}
|
||||
|
||||
static class ColorStateListFactory extends ConstantState<ColorStateList> {
|
||||
final ColorStateList mSrc;
|
||||
|
||||
public ColorStateListFactory(ColorStateList src) {
|
||||
mSrc = src;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChangingConfigurations() {
|
||||
return mSrc.mChangingConfigurations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorStateList newInstance() {
|
||||
return mSrc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorStateList newInstance(Resources res, Theme theme) {
|
||||
if (theme == null || !mSrc.canApplyTheme()) {
|
||||
return mSrc;
|
||||
}
|
||||
|
||||
final ColorStateList clone = new ColorStateList(mSrc);
|
||||
clone.applyTheme(theme);
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
@@ -386,6 +587,9 @@ public class ColorStateList implements Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
if (canApplyTheme()) {
|
||||
Log.w(TAG, "Wrote partially-resolved ColorStateList to parcel!");
|
||||
}
|
||||
final int N = mStateSpecs.length;
|
||||
dest.writeInt(N);
|
||||
for (int i = 0; i < N; i++) {
|
||||
|
||||
@@ -16,21 +16,20 @@
|
||||
|
||||
package android.content.res;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.StateListAnimator;
|
||||
import android.annotation.NonNull;
|
||||
import android.util.Pools.SynchronizedPool;
|
||||
import android.view.ViewDebug;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.StateListAnimator;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.ColorStateList.ColorStateListFactory;
|
||||
import android.graphics.Movie;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.Drawable.ConstantState;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
@@ -40,9 +39,11 @@ import android.util.ArrayMap;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.util.LongSparseArray;
|
||||
import android.util.Pools.SynchronizedPool;
|
||||
import android.util.Slog;
|
||||
import android.util.TypedValue;
|
||||
import android.util.LongSparseArray;
|
||||
import android.view.ViewDebug;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -97,8 +98,8 @@ public class Resources {
|
||||
private static final LongSparseArray<ConstantState>[] sPreloadedDrawables;
|
||||
private static final LongSparseArray<ConstantState> sPreloadedColorDrawables
|
||||
= new LongSparseArray<ConstantState>();
|
||||
private static final LongSparseArray<ColorStateList> sPreloadedColorStateLists
|
||||
= new LongSparseArray<ColorStateList>();
|
||||
private static final LongSparseArray<ColorStateListFactory> sPreloadedColorStateLists
|
||||
= new LongSparseArray<ColorStateListFactory>();
|
||||
|
||||
// Pool of TypedArrays targeted to this Resources object.
|
||||
final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<TypedArray>(5);
|
||||
@@ -116,8 +117,8 @@ public class Resources {
|
||||
new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>();
|
||||
private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> mColorDrawableCache =
|
||||
new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>();
|
||||
private final LongSparseArray<WeakReference<ColorStateList>> mColorStateListCache =
|
||||
new LongSparseArray<WeakReference<ColorStateList>>();
|
||||
private final ConfigurationBoundResourceCache<ColorStateList> mColorStateListCache =
|
||||
new ConfigurationBoundResourceCache<ColorStateList>(this);
|
||||
private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
|
||||
new ConfigurationBoundResourceCache<Animator>(this);
|
||||
private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
|
||||
@@ -897,20 +898,41 @@ public class Resources {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a color integer associated with a particular resource ID.
|
||||
* If the resource holds a complex
|
||||
* {@link android.content.res.ColorStateList}, then the default color from
|
||||
* the set is returned.
|
||||
* Returns a color integer associated with a particular resource ID. If the
|
||||
* resource holds a complex {@link ColorStateList}, then the default color
|
||||
* from the set is returned.
|
||||
*
|
||||
* @param id The desired resource identifier, as generated by the aapt
|
||||
* tool. This integer encodes the package, type, and resource
|
||||
* entry. The value 0 is an invalid identifier.
|
||||
*
|
||||
* @throws NotFoundException Throws NotFoundException if the given ID does not exist.
|
||||
* @throws NotFoundException Throws NotFoundException if the given ID does
|
||||
* not exist.
|
||||
*
|
||||
* @return Returns a single color value in the form 0xAARRGGBB.
|
||||
* @return A single color value in the form 0xAARRGGBB.
|
||||
* @deprecated Use {@link #getColor(int, Theme)} instead.
|
||||
*/
|
||||
public int getColor(int id) throws NotFoundException {
|
||||
return getColor(id, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a themed color integer associated with a particular resource ID.
|
||||
* If the resource holds a complex {@link ColorStateList}, then the default
|
||||
* color from the set is returned.
|
||||
*
|
||||
* @param id The desired resource identifier, as generated by the aapt
|
||||
* tool. This integer encodes the package, type, and resource
|
||||
* entry. The value 0 is an invalid identifier.
|
||||
* @param theme The theme used to style the color attributes, may be
|
||||
* {@code null}.
|
||||
*
|
||||
* @throws NotFoundException Throws NotFoundException if the given ID does
|
||||
* not exist.
|
||||
*
|
||||
* @return A single color value in the form 0xAARRGGBB.
|
||||
*/
|
||||
public int getColor(int id, @Nullable Theme theme) throws NotFoundException {
|
||||
TypedValue value;
|
||||
synchronized (mAccessLock) {
|
||||
value = mTmpValue;
|
||||
@@ -919,40 +941,77 @@ public class Resources {
|
||||
}
|
||||
getValue(id, value, true);
|
||||
if (value.type >= TypedValue.TYPE_FIRST_INT
|
||||
&& value.type <= TypedValue.TYPE_LAST_INT) {
|
||||
&& value.type <= TypedValue.TYPE_LAST_INT) {
|
||||
mTmpValue = value;
|
||||
return value.data;
|
||||
} else if (value.type != TypedValue.TYPE_STRING) {
|
||||
throw new NotFoundException(
|
||||
"Resource ID #0x" + Integer.toHexString(id) + " type #0x"
|
||||
+ Integer.toHexString(value.type) + " is not valid");
|
||||
"Resource ID #0x" + Integer.toHexString(id) + " type #0x"
|
||||
+ Integer.toHexString(value.type) + " is not valid");
|
||||
}
|
||||
mTmpValue = null;
|
||||
}
|
||||
ColorStateList csl = loadColorStateList(value, id);
|
||||
|
||||
final ColorStateList csl = loadColorStateList(value, id, theme);
|
||||
synchronized (mAccessLock) {
|
||||
if (mTmpValue == null) {
|
||||
mTmpValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
return csl.getDefaultColor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a color state list associated with a particular resource ID. The
|
||||
* resource may contain either a single raw color value, or a complex
|
||||
* {@link android.content.res.ColorStateList} holding multiple possible colors.
|
||||
* Returns a color state list associated with a particular resource ID. The
|
||||
* resource may contain either a single raw color value or a complex
|
||||
* {@link ColorStateList} holding multiple possible colors.
|
||||
*
|
||||
* @param id The desired resource identifier of a {@link ColorStateList},
|
||||
* as generated by the aapt tool. This integer encodes the package, type, and resource
|
||||
* entry. The value 0 is an invalid identifier.
|
||||
* as generated by the aapt tool. This integer encodes the
|
||||
* package, type, and resource entry. The value 0 is an invalid
|
||||
* identifier.
|
||||
*
|
||||
* @throws NotFoundException Throws NotFoundException if the given ID does not exist.
|
||||
* @throws NotFoundException Throws NotFoundException if the given ID does
|
||||
* not exist.
|
||||
*
|
||||
* @return Returns a ColorStateList object containing either a single
|
||||
* solid color or multiple colors that can be selected based on a state.
|
||||
* @return A ColorStateList object containing either a single solid color
|
||||
* or multiple colors that can be selected based on a state.
|
||||
* @deprecated Use {@link #getColorStateList(int, Theme)} instead.
|
||||
*/
|
||||
@Nullable
|
||||
public ColorStateList getColorStateList(int id) throws NotFoundException {
|
||||
final ColorStateList csl = getColorStateList(id, null);
|
||||
if (csl != null && csl.canApplyTheme()) {
|
||||
Log.w(TAG, "ColorStateList " + getResourceName(id) + " has "
|
||||
+ "unresolved theme attributes! Consider using "
|
||||
+ "Resources.getColorStateList(int, Theme) or "
|
||||
+ "Context.getColorStateList(int).", new RuntimeException());
|
||||
}
|
||||
return csl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a themed color state list associated with a particular resource
|
||||
* ID. The resource may contain either a single raw color value or a
|
||||
* complex {@link ColorStateList} holding multiple possible colors.
|
||||
*
|
||||
* @param id The desired resource identifier of a {@link ColorStateList},
|
||||
* as generated by the aapt tool. This integer encodes the
|
||||
* package, type, and resource entry. The value 0 is an invalid
|
||||
* identifier.
|
||||
* @param theme The theme used to style the color attributes, may be
|
||||
* {@code null}.
|
||||
*
|
||||
* @throws NotFoundException Throws NotFoundException if the given ID does
|
||||
* not exist.
|
||||
*
|
||||
* @return A themed ColorStateList object containing either a single solid
|
||||
* color or multiple colors that can be selected based on a state.
|
||||
*/
|
||||
@Nullable
|
||||
public ColorStateList getColorStateList(int id, @Nullable Theme theme)
|
||||
throws NotFoundException {
|
||||
TypedValue value;
|
||||
synchronized (mAccessLock) {
|
||||
value = mTmpValue;
|
||||
@@ -963,15 +1022,19 @@ public class Resources {
|
||||
}
|
||||
getValue(id, value, true);
|
||||
}
|
||||
ColorStateList res = loadColorStateList(value, id);
|
||||
|
||||
final ColorStateList res = loadColorStateList(value, id, theme);
|
||||
synchronized (mAccessLock) {
|
||||
if (mTmpValue == null) {
|
||||
mTmpValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return a boolean associated with a particular resource ID. This can be
|
||||
* used with any integral resource value, and will return true if it is
|
||||
@@ -1843,11 +1906,10 @@ public class Resources {
|
||||
|
||||
clearDrawableCachesLocked(mDrawableCache, configChanges);
|
||||
clearDrawableCachesLocked(mColorDrawableCache, configChanges);
|
||||
mColorStateListCache.onConfigurationChange(configChanges);
|
||||
mAnimatorCache.onConfigurationChange(configChanges);
|
||||
mStateListAnimatorCache.onConfigurationChange(configChanges);
|
||||
|
||||
mColorStateListCache.clear();
|
||||
|
||||
flushLayoutCache();
|
||||
}
|
||||
synchronized (sSync) {
|
||||
@@ -2476,7 +2538,7 @@ public class Resources {
|
||||
private Drawable loadDrawableForCookie(TypedValue value, int id, Theme theme) {
|
||||
if (value.string == null) {
|
||||
throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
|
||||
+ Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
|
||||
+ Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
|
||||
}
|
||||
|
||||
final String file = value.string.toString();
|
||||
@@ -2567,7 +2629,8 @@ public class Resources {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*package*/ ColorStateList loadColorStateList(TypedValue value, int id)
|
||||
@Nullable
|
||||
ColorStateList loadColorStateList(TypedValue value, int id, Theme theme)
|
||||
throws NotFoundException {
|
||||
if (TRACE_FOR_PRELOAD) {
|
||||
// Log only framework resources
|
||||
@@ -2581,99 +2644,105 @@ public class Resources {
|
||||
|
||||
ColorStateList csl;
|
||||
|
||||
if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
|
||||
value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
|
||||
|
||||
csl = sPreloadedColorStateLists.get(key);
|
||||
if (csl != null) {
|
||||
return csl;
|
||||
// Handle inline color definitions.
|
||||
if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
|
||||
&& value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
|
||||
final ColorStateListFactory factory = sPreloadedColorStateLists.get(key);
|
||||
if (factory != null) {
|
||||
return factory.newInstance();
|
||||
}
|
||||
|
||||
csl = ColorStateList.valueOf(value.data);
|
||||
|
||||
if (mPreloading) {
|
||||
if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
|
||||
"color")) {
|
||||
sPreloadedColorStateLists.put(key, csl);
|
||||
sPreloadedColorStateLists.put(key, csl.getFactory());
|
||||
}
|
||||
}
|
||||
|
||||
return csl;
|
||||
}
|
||||
|
||||
csl = getCachedColorStateList(key);
|
||||
final ConfigurationBoundResourceCache<ColorStateList> cache = mColorStateListCache;
|
||||
|
||||
csl = cache.get(key, theme);
|
||||
if (csl != null) {
|
||||
return csl;
|
||||
}
|
||||
|
||||
csl = sPreloadedColorStateLists.get(key);
|
||||
if (csl != null) {
|
||||
return csl;
|
||||
final ColorStateListFactory factory = sPreloadedColorStateLists.get(key);
|
||||
if (factory != null) {
|
||||
csl = factory.newInstance(this, theme);
|
||||
}
|
||||
|
||||
if (value.string == null) {
|
||||
throw new NotFoundException(
|
||||
"Resource is not a ColorStateList (color or path): " + value);
|
||||
}
|
||||
|
||||
final String file = value.string.toString();
|
||||
|
||||
if (file.endsWith(".xml")) {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
|
||||
try {
|
||||
final XmlResourceParser rp = loadXmlResourceParser(
|
||||
file, id, value.assetCookie, "colorstatelist");
|
||||
csl = ColorStateList.createFromXml(this, rp);
|
||||
rp.close();
|
||||
} catch (Exception e) {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
|
||||
NotFoundException rnf = new NotFoundException(
|
||||
"File " + file + " from color state list resource ID #0x"
|
||||
+ Integer.toHexString(id));
|
||||
rnf.initCause(e);
|
||||
throw rnf;
|
||||
}
|
||||
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
|
||||
} else {
|
||||
throw new NotFoundException(
|
||||
"File " + file + " from drawable resource ID #0x"
|
||||
+ Integer.toHexString(id) + ": .xml extension required");
|
||||
if (csl == null) {
|
||||
csl = loadColorStateListForCookie(value, id, theme);
|
||||
}
|
||||
|
||||
if (csl != null) {
|
||||
if (mPreloading) {
|
||||
if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
|
||||
"color")) {
|
||||
sPreloadedColorStateLists.put(key, csl);
|
||||
sPreloadedColorStateLists.put(key, csl.getFactory());
|
||||
}
|
||||
} else {
|
||||
synchronized (mAccessLock) {
|
||||
//Log.i(TAG, "Saving cached color state list @ #" +
|
||||
// Integer.toHexString(key.intValue())
|
||||
// + " in " + this + ": " + csl);
|
||||
mColorStateListCache.put(key, new WeakReference<ColorStateList>(csl));
|
||||
}
|
||||
cache.put(key, theme, csl.getFactory());
|
||||
}
|
||||
}
|
||||
|
||||
return csl;
|
||||
}
|
||||
|
||||
private ColorStateList getCachedColorStateList(long key) {
|
||||
synchronized (mAccessLock) {
|
||||
WeakReference<ColorStateList> wr = mColorStateListCache.get(key);
|
||||
if (wr != null) { // we have the key
|
||||
ColorStateList entry = wr.get();
|
||||
if (entry != null) {
|
||||
//Log.i(TAG, "Returning cached color state list @ #" +
|
||||
// Integer.toHexString(((Integer)key).intValue())
|
||||
// + " in " + this + ": " + entry);
|
||||
return entry;
|
||||
} else { // our entry has been purged
|
||||
mColorStateListCache.delete(key);
|
||||
private ColorStateList loadColorStateListForCookie(TypedValue value, int id, Theme theme) {
|
||||
if (value.string == null) {
|
||||
throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
|
||||
+ Integer.toHexString(id) + ") is not a ColorStateList: " + value);
|
||||
}
|
||||
|
||||
final String file = value.string.toString();
|
||||
|
||||
if (TRACE_FOR_MISS_PRELOAD) {
|
||||
// Log only framework resources
|
||||
if ((id >>> 24) == 0x1) {
|
||||
final String name = getResourceName(id);
|
||||
if (name != null) {
|
||||
Log.d(TAG, "Loading framework color state list #" + Integer.toHexString(id)
|
||||
+ ": " + name + " at " + file);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
if (DEBUG_LOAD) {
|
||||
Log.v(TAG, "Loading color state list for cookie " + value.assetCookie + ": " + file);
|
||||
}
|
||||
|
||||
final ColorStateList csl;
|
||||
|
||||
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
|
||||
if (file.endsWith(".xml")) {
|
||||
try {
|
||||
final XmlResourceParser rp = loadXmlResourceParser(
|
||||
file, id, value.assetCookie, "colorstatelist");
|
||||
csl = ColorStateList.createFromXml(this, rp, theme);
|
||||
rp.close();
|
||||
} catch (Exception e) {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
|
||||
final NotFoundException rnf = new NotFoundException(
|
||||
"File " + file + " from color state list resource ID #0x"
|
||||
+ Integer.toHexString(id));
|
||||
rnf.initCause(e);
|
||||
throw rnf;
|
||||
}
|
||||
} else {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
|
||||
throw new NotFoundException(
|
||||
"File " + file + " from drawable resource ID #0x"
|
||||
+ Integer.toHexString(id) + ": .xml extension required");
|
||||
}
|
||||
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
|
||||
|
||||
return csl;
|
||||
}
|
||||
|
||||
/*package*/ XmlResourceParser loadXmlResourceParser(int id, String type)
|
||||
@@ -2752,6 +2821,20 @@ public class Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains styled attributes from the theme, if available, or unstyled
|
||||
* resources if the theme is null.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static TypedArray obtainAttributes(
|
||||
Resources res, Theme theme, AttributeSet set, int[] attrs) {
|
||||
if (theme == null) {
|
||||
return res.obtainAttributes(set, attrs);
|
||||
}
|
||||
return theme.obtainStyledAttributes(set, attrs, 0, 0);
|
||||
}
|
||||
|
||||
private Resources() {
|
||||
mAssets = AssetManager.getSystem();
|
||||
// NOTE: Intentionally leaving this uninitialized (all values set
|
||||
|
||||
@@ -392,8 +392,8 @@ public class TypedArray {
|
||||
} else if (type == TypedValue.TYPE_STRING) {
|
||||
final TypedValue value = mValue;
|
||||
if (getValueAt(index, value)) {
|
||||
ColorStateList csl = mResources.loadColorStateList(
|
||||
value, value.resourceId);
|
||||
final ColorStateList csl = mResources.loadColorStateList(
|
||||
value, value.resourceId, mTheme);
|
||||
return csl.getDefaultColor();
|
||||
}
|
||||
return defValue;
|
||||
@@ -424,7 +424,7 @@ public class TypedArray {
|
||||
if (value.type == TypedValue.TYPE_ATTRIBUTE) {
|
||||
throw new RuntimeException("Failed to resolve attribute at index " + index);
|
||||
}
|
||||
return mResources.loadColorStateList(value, value.resourceId);
|
||||
return mResources.loadColorStateList(value, value.resourceId, mTheme);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -905,12 +905,21 @@ public class TypedArray {
|
||||
* Removes the entries from the typed array so that subsequent calls to typed
|
||||
* getters will return the default value without crashing.
|
||||
*
|
||||
* @return an array of length {@link #getIndexCount()} populated with theme
|
||||
* attributes, or null if there are no theme attributes in the typed
|
||||
* array
|
||||
* @return An array of length {@link #getIndexCount()} populated with theme
|
||||
* attributes, or {@code null} if there are no theme attributes in
|
||||
* the typed array.
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
public int[] extractThemeAttrs() {
|
||||
return extractThemeAttrs(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
public int[] extractThemeAttrs(@Nullable int[] scrap) {
|
||||
if (mRecycled) {
|
||||
throw new RuntimeException("Cannot make calls to a recycled instance!");
|
||||
}
|
||||
@@ -922,6 +931,7 @@ public class TypedArray {
|
||||
for (int i = 0; i < N; i++) {
|
||||
final int index = i * AssetManager.STYLE_NUM_ENTRIES;
|
||||
if (data[index + AssetManager.STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) {
|
||||
// Not an attribute, ignore.
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -930,13 +940,20 @@ public class TypedArray {
|
||||
|
||||
final int attr = data[index + AssetManager.STYLE_DATA];
|
||||
if (attr == 0) {
|
||||
// This attribute is useless!
|
||||
// Useless data, ignore.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ensure we have a usable attribute array.
|
||||
if (attrs == null) {
|
||||
attrs = new int[N];
|
||||
if (scrap != null && scrap.length == N) {
|
||||
attrs = scrap;
|
||||
Arrays.fill(attrs, 0);
|
||||
} else {
|
||||
attrs = new int[N];
|
||||
}
|
||||
}
|
||||
|
||||
attrs[i] = attr;
|
||||
}
|
||||
|
||||
|
||||
22
core/res/res/color/btn_material_accent.xml
Normal file
22
core/res/res/color/btn_material_accent.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2014 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="false"
|
||||
android:alpha="?attr/disabledAlpha"
|
||||
android:color="@color/button_material_dark" />
|
||||
<item android:color="?attr/colorAccent" />
|
||||
</selector>
|
||||
@@ -4890,6 +4890,14 @@
|
||||
<attr name="animation"/>
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Attributes that can be assigned to a ColorStateList item. -->
|
||||
<declare-styleable name="ColorStateListItem">
|
||||
<!-- Base color for this state. -->
|
||||
<attr name="color" />
|
||||
<!-- Alpha multiplier applied to the base color. -->
|
||||
<attr name="alpha" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Drawable used to render a geometric shape, with a gradient or a solid color. -->
|
||||
<declare-styleable name="GradientDrawable">
|
||||
<!-- Indicates whether the drawable should intially be visible. -->
|
||||
|
||||
@@ -2598,4 +2598,11 @@
|
||||
<public type="style" name="Theme.DeviceDefault.Dialog.Alert" />
|
||||
<public type="style" name="Theme.DeviceDefault.Light.Dialog.Alert" />
|
||||
|
||||
<!-- ===============================================================
|
||||
Resources added in version MNC of the platform
|
||||
=============================================================== -->
|
||||
<eat-comment />
|
||||
|
||||
<public type="style" name="Widget.Material.Button.Colored" />
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -462,6 +462,11 @@ please see styles_device_defaults.xml.
|
||||
<item name="gravity">center_vertical|center_horizontal</item>
|
||||
</style>
|
||||
|
||||
<!-- Colored bordered ink button -->
|
||||
<style name="Widget.Material.Button.Colored">
|
||||
<item name="backgroundTint">@color/btn_material_accent</item>
|
||||
</style>
|
||||
|
||||
<!-- Small bordered ink button -->
|
||||
<style name="Widget.Material.Button.Small">
|
||||
<item name="minHeight">48dip</item>
|
||||
|
||||
@@ -705,8 +705,8 @@ public class BitmapDrawable extends Drawable {
|
||||
|
||||
@Override
|
||||
public boolean isStateful() {
|
||||
final BitmapState s = mBitmapState;
|
||||
return super.isStateful() || (s.mTint != null && s.mTint.isStateful());
|
||||
return (mBitmapState.mTint != null && mBitmapState.mTint.isStateful())
|
||||
|| super.isStateful();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -718,6 +718,9 @@ public class BitmapDrawable extends Drawable {
|
||||
updateStateFromTypedArray(a);
|
||||
verifyState(a);
|
||||
a.recycle();
|
||||
|
||||
// Update local properties.
|
||||
updateLocalState(r);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -800,9 +803,6 @@ public class BitmapDrawable extends Drawable {
|
||||
if (tileModeY != TILE_MODE_UNDEFINED) {
|
||||
setTileModeY(parseTileMode(tileModeY));
|
||||
}
|
||||
|
||||
// Update local properties.
|
||||
initializeWithState(state, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -810,18 +810,28 @@ public class BitmapDrawable extends Drawable {
|
||||
super.applyTheme(t);
|
||||
|
||||
final BitmapState state = mBitmapState;
|
||||
if (state == null || state.mThemeAttrs == null) {
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.BitmapDrawable);
|
||||
try {
|
||||
updateStateFromTypedArray(a);
|
||||
} catch (XmlPullParserException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
a.recycle();
|
||||
if (state.mThemeAttrs != null) {
|
||||
final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.BitmapDrawable);
|
||||
try {
|
||||
updateStateFromTypedArray(a);
|
||||
} catch (XmlPullParserException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
// Apply theme to contained color state list.
|
||||
if (state.mTint != null && state.mTint.canApplyTheme()) {
|
||||
state.mTint.applyTheme(t);
|
||||
}
|
||||
|
||||
// Update local properties.
|
||||
updateLocalState(t.getResources());
|
||||
}
|
||||
|
||||
private static Shader.TileMode parseTileMode(int tileMode) {
|
||||
@@ -839,7 +849,7 @@ public class BitmapDrawable extends Drawable {
|
||||
|
||||
@Override
|
||||
public boolean canApplyTheme() {
|
||||
return mBitmapState != null && mBitmapState.mThemeAttrs != null;
|
||||
return mBitmapState != null && mBitmapState.canApplyTheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -910,7 +920,7 @@ public class BitmapDrawable extends Drawable {
|
||||
|
||||
@Override
|
||||
public boolean canApplyTheme() {
|
||||
return mThemeAttrs != null;
|
||||
return mThemeAttrs != null || mTint != null && mTint.canApplyTheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -944,7 +954,7 @@ public class BitmapDrawable extends Drawable {
|
||||
private BitmapDrawable(BitmapState state, Resources res) {
|
||||
mBitmapState = state;
|
||||
|
||||
initializeWithState(mBitmapState, res);
|
||||
updateLocalState(res);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -952,14 +962,14 @@ public class BitmapDrawable extends Drawable {
|
||||
* after significant state changes, e.g. from the One True Constructor and
|
||||
* after inflating or applying a theme.
|
||||
*/
|
||||
private void initializeWithState(BitmapState state, Resources res) {
|
||||
private void updateLocalState(Resources res) {
|
||||
if (res != null) {
|
||||
mTargetDensity = res.getDisplayMetrics().densityDpi;
|
||||
} else {
|
||||
mTargetDensity = state.mTargetDensity;
|
||||
mTargetDensity = mBitmapState.mTargetDensity;
|
||||
}
|
||||
|
||||
mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
|
||||
mTintFilter = updateTintFilter(mTintFilter, mBitmapState.mTint, mBitmapState.mTintMode);
|
||||
computeBitmapSize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public class ColorDrawable extends Drawable {
|
||||
|
||||
@Override
|
||||
public int getChangingConfigurations() {
|
||||
return super.getChangingConfigurations() | mColorState.mChangingConfigurations;
|
||||
return super.getChangingConfigurations() | mColorState.getChangingConfigurations();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,6 +233,8 @@ public class ColorDrawable extends Drawable {
|
||||
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ColorDrawable);
|
||||
updateStateFromTypedArray(a);
|
||||
a.recycle();
|
||||
|
||||
updateLocalState(r);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,13 +263,21 @@ public class ColorDrawable extends Drawable {
|
||||
super.applyTheme(t);
|
||||
|
||||
final ColorState state = mColorState;
|
||||
if (state == null || state.mThemeAttrs == null) {
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ColorDrawable);
|
||||
updateStateFromTypedArray(a);
|
||||
a.recycle();
|
||||
if (state.mThemeAttrs != null) {
|
||||
final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ColorDrawable);
|
||||
updateStateFromTypedArray(a);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
if (state.mTint != null && state.mTint.canApplyTheme()) {
|
||||
state.mTint.applyTheme(t);
|
||||
}
|
||||
|
||||
updateLocalState(t.getResources());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -299,17 +309,18 @@ public class ColorDrawable extends Drawable {
|
||||
|
||||
@Override
|
||||
public boolean canApplyTheme() {
|
||||
return mThemeAttrs != null;
|
||||
return mThemeAttrs != null
|
||||
|| (mTint != null && mTint.canApplyTheme());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable newDrawable() {
|
||||
return new ColorDrawable(this);
|
||||
return new ColorDrawable(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable newDrawable(Resources res) {
|
||||
return new ColorDrawable(this);
|
||||
return new ColorDrawable(this, res);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -318,8 +329,18 @@ public class ColorDrawable extends Drawable {
|
||||
}
|
||||
}
|
||||
|
||||
private ColorDrawable(ColorState state) {
|
||||
private ColorDrawable(ColorState state, Resources res) {
|
||||
mColorState = state;
|
||||
mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
|
||||
|
||||
updateLocalState(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes local dynamic properties from state. This should be called
|
||||
* after significant state changes, e.g. from the One True Constructor and
|
||||
* after inflating or applying a theme.
|
||||
*/
|
||||
private void updateLocalState(Resources r) {
|
||||
mTintFilter = updateTintFilter(mTintFilter, mColorState.mTint, mColorState.mTintMode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ public class GradientDrawable extends Drawable {
|
||||
private final RectF mRect = new RectF();
|
||||
|
||||
private Paint mLayerPaint; // internal, used if we use saveLayer()
|
||||
private boolean mGradientIsDirty; // internal state
|
||||
private boolean mGradientIsDirty;
|
||||
private boolean mMutated;
|
||||
private Path mRingPath;
|
||||
private boolean mPathIsDirty = true;
|
||||
@@ -174,7 +174,7 @@ public class GradientDrawable extends Drawable {
|
||||
}
|
||||
|
||||
public GradientDrawable() {
|
||||
this(new GradientState(Orientation.TOP_BOTTOM, null));
|
||||
this(new GradientState(Orientation.TOP_BOTTOM, null), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,7 +182,7 @@ public class GradientDrawable extends Drawable {
|
||||
* of colors for the gradient.
|
||||
*/
|
||||
public GradientDrawable(Orientation orientation, int[] colors) {
|
||||
this(new GradientState(orientation, colors));
|
||||
this(new GradientState(orientation, colors), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1018,7 +1018,7 @@ public class GradientDrawable extends Drawable {
|
||||
|
||||
inflateChildElements(r, parser, attrs, theme);
|
||||
|
||||
mGradientState.computeOpacity();
|
||||
updateLocalState(r);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1037,9 +1037,21 @@ public class GradientDrawable extends Drawable {
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
if (state.mTint != null && state.mTint.canApplyTheme()) {
|
||||
state.mTint.applyTheme(t);
|
||||
}
|
||||
|
||||
if (state.mColorStateList != null && state.mColorStateList.canApplyTheme()) {
|
||||
state.mColorStateList.applyTheme(t);
|
||||
}
|
||||
|
||||
if (state.mStrokeColorStateList != null && state.mStrokeColorStateList.canApplyTheme()) {
|
||||
state.mStrokeColorStateList.applyTheme(t);
|
||||
}
|
||||
|
||||
applyThemeChildElements(t);
|
||||
|
||||
state.computeOpacity();
|
||||
updateLocalState(t.getResources());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1087,8 +1099,6 @@ public class GradientDrawable extends Drawable {
|
||||
if (tint != null) {
|
||||
state.mTint = tint;
|
||||
}
|
||||
|
||||
mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1516,7 +1526,7 @@ public class GradientDrawable extends Drawable {
|
||||
public Drawable mutate() {
|
||||
if (!mMutated && super.mutate() == this) {
|
||||
mGradientState = new GradientState(mGradientState);
|
||||
initializeWithState(mGradientState);
|
||||
updateLocalState(null);
|
||||
mMutated = true;
|
||||
}
|
||||
return this;
|
||||
@@ -1577,7 +1587,7 @@ public class GradientDrawable extends Drawable {
|
||||
int[] mAttrCorners;
|
||||
int[] mAttrPadding;
|
||||
|
||||
GradientState(Orientation orientation, int[] colors) {
|
||||
public GradientState(Orientation orientation, int[] colors) {
|
||||
mOrientation = orientation;
|
||||
setColors(colors);
|
||||
}
|
||||
@@ -1634,19 +1644,24 @@ public class GradientDrawable extends Drawable {
|
||||
|
||||
@Override
|
||||
public boolean canApplyTheme() {
|
||||
return mThemeAttrs != null || mAttrSize != null || mAttrGradient != null
|
||||
|| mAttrSolid != null || mAttrStroke != null || mAttrCorners != null
|
||||
|| mAttrPadding != null || super.canApplyTheme();
|
||||
return mThemeAttrs != null
|
||||
|| mAttrSize != null || mAttrGradient != null
|
||||
|| mAttrSolid != null || mAttrStroke != null
|
||||
|| mAttrCorners != null || mAttrPadding != null
|
||||
|| (mTint != null && mTint.canApplyTheme())
|
||||
|| (mStrokeColorStateList != null && mStrokeColorStateList.canApplyTheme())
|
||||
|| (mColorStateList != null && mColorStateList.canApplyTheme())
|
||||
|| super.canApplyTheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable newDrawable() {
|
||||
return new GradientDrawable(this);
|
||||
return new GradientDrawable(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable newDrawable(Resources res) {
|
||||
return new GradientDrawable(this);
|
||||
return new GradientDrawable(this, res);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1751,16 +1766,15 @@ public class GradientDrawable extends Drawable {
|
||||
*
|
||||
* @param state Constant state from which the drawable inherits
|
||||
*/
|
||||
private GradientDrawable(GradientState state) {
|
||||
private GradientDrawable(GradientState state, Resources res) {
|
||||
mGradientState = state;
|
||||
|
||||
initializeWithState(mGradientState);
|
||||
|
||||
mGradientIsDirty = true;
|
||||
mMutated = false;
|
||||
updateLocalState(res);
|
||||
}
|
||||
|
||||
private void initializeWithState(GradientState state) {
|
||||
private void updateLocalState(Resources res) {
|
||||
final GradientState state = mGradientState;
|
||||
|
||||
if (state.mColorStateList != null) {
|
||||
final int[] currentState = getState();
|
||||
final int stateColor = state.mColorStateList.getColorForState(currentState, 0);
|
||||
@@ -1797,5 +1811,8 @@ public class GradientDrawable extends Drawable {
|
||||
}
|
||||
|
||||
mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
|
||||
mGradientIsDirty = true;
|
||||
|
||||
state.computeOpacity();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,6 +401,8 @@ public class NinePatchDrawable extends Drawable {
|
||||
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.NinePatchDrawable);
|
||||
updateStateFromTypedArray(a);
|
||||
a.recycle();
|
||||
|
||||
updateLocalState(r);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -467,12 +469,6 @@ public class NinePatchDrawable extends Drawable {
|
||||
if (tint != null) {
|
||||
state.mTint = tint;
|
||||
}
|
||||
|
||||
// Update local properties.
|
||||
initializeWithState(state, r);
|
||||
|
||||
// Push density applied by setNinePatchState into state.
|
||||
state.mTargetDensity = mTargetDensity;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -480,23 +476,32 @@ public class NinePatchDrawable extends Drawable {
|
||||
super.applyTheme(t);
|
||||
|
||||
final NinePatchState state = mNinePatchState;
|
||||
if (state == null || state.mThemeAttrs == null) {
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.NinePatchDrawable);
|
||||
try {
|
||||
updateStateFromTypedArray(a);
|
||||
} catch (XmlPullParserException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
a.recycle();
|
||||
if (state.mThemeAttrs != null) {
|
||||
final TypedArray a = t.resolveAttributes(
|
||||
state.mThemeAttrs, R.styleable.NinePatchDrawable);
|
||||
try {
|
||||
updateStateFromTypedArray(a);
|
||||
} catch (XmlPullParserException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
if (state.mTint != null && state.mTint.canApplyTheme()) {
|
||||
state.mTint.applyTheme(t);
|
||||
}
|
||||
|
||||
updateLocalState(t.getResources());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canApplyTheme() {
|
||||
return mNinePatchState != null && mNinePatchState.mThemeAttrs != null;
|
||||
return mNinePatchState != null && mNinePatchState.canApplyTheme();
|
||||
}
|
||||
|
||||
public Paint getPaint() {
|
||||
@@ -645,7 +650,8 @@ public class NinePatchDrawable extends Drawable {
|
||||
|
||||
@Override
|
||||
public boolean canApplyTheme() {
|
||||
return mThemeAttrs != null;
|
||||
return mThemeAttrs != null
|
||||
|| (mTint != null && mTint.canApplyTheme());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -680,19 +686,25 @@ public class NinePatchDrawable extends Drawable {
|
||||
private NinePatchDrawable(NinePatchState state, Resources res) {
|
||||
mNinePatchState = state;
|
||||
|
||||
initializeWithState(mNinePatchState, res);
|
||||
updateLocalState(res);
|
||||
|
||||
// Push density applied by setNinePatchState into state.
|
||||
mNinePatchState.mTargetDensity = mTargetDensity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes local dynamic properties from state.
|
||||
*/
|
||||
private void initializeWithState(NinePatchState state, Resources res) {
|
||||
private void updateLocalState(Resources res) {
|
||||
final NinePatchState state = mNinePatchState;
|
||||
|
||||
if (res != null) {
|
||||
mTargetDensity = res.getDisplayMetrics().densityDpi;
|
||||
} else {
|
||||
mTargetDensity = state.mTargetDensity;
|
||||
}
|
||||
|
||||
|
||||
// If we can, avoid calling any methods that initialize Paint.
|
||||
if (state.mDither != DEFAULT_DITHER) {
|
||||
setDither(state.mDither);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -198,7 +198,7 @@ public class RippleDrawable extends LayerDrawable {
|
||||
|
||||
setColor(color);
|
||||
ensurePadding();
|
||||
initializeFromState();
|
||||
updateLocalState();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -352,6 +352,11 @@ public class RippleDrawable extends LayerDrawable {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ripple color.
|
||||
*
|
||||
* @param color Ripple color as a color state list.
|
||||
*/
|
||||
public void setColor(ColorStateList color) {
|
||||
mState.mColor = color;
|
||||
invalidateSelf();
|
||||
@@ -370,7 +375,8 @@ public class RippleDrawable extends LayerDrawable {
|
||||
super.inflate(r, parser, attrs, theme);
|
||||
|
||||
setTargetDensity(r.getDisplayMetrics());
|
||||
initializeFromState();
|
||||
|
||||
updateLocalState();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -450,21 +456,27 @@ public class RippleDrawable extends LayerDrawable {
|
||||
super.applyTheme(t);
|
||||
|
||||
final RippleState state = mState;
|
||||
if (state == null || state.mTouchThemeAttrs == null) {
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final TypedArray a = t.resolveAttributes(state.mTouchThemeAttrs,
|
||||
R.styleable.RippleDrawable);
|
||||
try {
|
||||
updateStateFromTypedArray(a);
|
||||
} catch (XmlPullParserException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
a.recycle();
|
||||
if (state.mTouchThemeAttrs != null) {
|
||||
final TypedArray a = t.resolveAttributes(state.mTouchThemeAttrs,
|
||||
R.styleable.RippleDrawable);
|
||||
try {
|
||||
updateStateFromTypedArray(a);
|
||||
} catch (XmlPullParserException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
initializeFromState();
|
||||
if (state.mColor != null && state.mColor.canApplyTheme()) {
|
||||
state.mColor.applyTheme(t);
|
||||
}
|
||||
|
||||
updateLocalState();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -931,7 +943,9 @@ public class RippleDrawable extends LayerDrawable {
|
||||
|
||||
@Override
|
||||
public boolean canApplyTheme() {
|
||||
return mTouchThemeAttrs != null || super.canApplyTheme();
|
||||
return mTouchThemeAttrs != null
|
||||
|| (mColor != null && mColor.canApplyTheme())
|
||||
|| super.canApplyTheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -987,10 +1001,10 @@ public class RippleDrawable extends LayerDrawable {
|
||||
mDensity = res.getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
initializeFromState();
|
||||
updateLocalState();
|
||||
}
|
||||
|
||||
private void initializeFromState() {
|
||||
private void updateLocalState() {
|
||||
// Initialize from constant state.
|
||||
mMask = findDrawableByLayerId(R.id.mask);
|
||||
}
|
||||
|
||||
@@ -402,7 +402,7 @@ public class ShapeDrawable extends Drawable {
|
||||
}
|
||||
|
||||
// Update local properties.
|
||||
initializeWithState(mShapeState, r);
|
||||
updateLocalState(r);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -410,16 +410,23 @@ public class ShapeDrawable extends Drawable {
|
||||
super.applyTheme(t);
|
||||
|
||||
final ShapeState state = mShapeState;
|
||||
if (state == null || state.mThemeAttrs == null) {
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ShapeDrawable);
|
||||
updateStateFromTypedArray(a);
|
||||
a.recycle();
|
||||
if (state.mThemeAttrs != null) {
|
||||
final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ShapeDrawable);
|
||||
updateStateFromTypedArray(a);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
// Apply theme to contained color state list.
|
||||
if (state.mTint != null && state.mTint.canApplyTheme()) {
|
||||
state.mTint.applyTheme(t);
|
||||
}
|
||||
|
||||
// Update local properties.
|
||||
initializeWithState(state, t.getResources());
|
||||
updateLocalState(t.getResources());
|
||||
}
|
||||
|
||||
private void updateStateFromTypedArray(TypedArray a) {
|
||||
@@ -550,7 +557,8 @@ public class ShapeDrawable extends Drawable {
|
||||
|
||||
@Override
|
||||
public boolean canApplyTheme() {
|
||||
return mThemeAttrs != null;
|
||||
return mThemeAttrs != null
|
||||
|| (mTint != null && mTint.canApplyTheme());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -576,7 +584,7 @@ public class ShapeDrawable extends Drawable {
|
||||
private ShapeDrawable(ShapeState state, Resources res) {
|
||||
mShapeState = state;
|
||||
|
||||
initializeWithState(state, res);
|
||||
updateLocalState(res);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -584,8 +592,8 @@ public class ShapeDrawable extends Drawable {
|
||||
* after significant state changes, e.g. from the One True Constructor and
|
||||
* after inflating or applying a theme.
|
||||
*/
|
||||
private void initializeWithState(ShapeState state, Resources res) {
|
||||
mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
|
||||
private void updateLocalState(Resources res) {
|
||||
mTintFilter = updateTintFilter(mTintFilter, mShapeState.mTint, mShapeState.mTintMode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -369,8 +369,13 @@ public class VectorDrawable extends Drawable {
|
||||
super.applyTheme(t);
|
||||
|
||||
final VectorDrawableState state = mVectorState;
|
||||
if (state != null && state.mThemeAttrs != null) {
|
||||
final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.VectorDrawable);
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.mThemeAttrs != null) {
|
||||
final TypedArray a = t.resolveAttributes(
|
||||
state.mThemeAttrs, R.styleable.VectorDrawable);
|
||||
try {
|
||||
state.mCacheDirty = true;
|
||||
updateStateFromTypedArray(a);
|
||||
@@ -379,14 +384,20 @@ public class VectorDrawable extends Drawable {
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
|
||||
// Apply theme to contained color state list.
|
||||
if (state.mTint != null && state.mTint.canApplyTheme()) {
|
||||
state.mTint.applyTheme(t);
|
||||
}
|
||||
|
||||
final VPathRenderer path = state.mVPathRenderer;
|
||||
if (path != null && path.canApplyTheme()) {
|
||||
path.applyTheme(t);
|
||||
}
|
||||
|
||||
// Update local state.
|
||||
mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -750,7 +761,9 @@ public class VectorDrawable extends Drawable {
|
||||
|
||||
@Override
|
||||
public boolean canApplyTheme() {
|
||||
return mThemeAttrs != null || (mVPathRenderer != null && mVPathRenderer.canApplyTheme())
|
||||
return mThemeAttrs != null
|
||||
|| (mVPathRenderer != null && mVPathRenderer.canApplyTheme())
|
||||
|| (mTint != null && mTint.canApplyTheme())
|
||||
|| super.canApplyTheme();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user