Always resolve enum when resolving resources.
Enums were resolved only for integers and dimensions. This change resolves enums for all resource types. Well, almost all. For color and colorStateList, enums are still not referenced. Bug: http://b.android.com/76091 Change-Id: Ie43bd1b54fb9877655d31773bdf71d9a6a65c473
This commit is contained in:
@@ -23,7 +23,6 @@ import com.android.ide.common.rendering.api.ResourceValue;
|
|||||||
import com.android.ide.common.rendering.api.StyleResourceValue;
|
import com.android.ide.common.rendering.api.StyleResourceValue;
|
||||||
import com.android.internal.util.XmlUtils;
|
import com.android.internal.util.XmlUtils;
|
||||||
import com.android.layoutlib.bridge.Bridge;
|
import com.android.layoutlib.bridge.Bridge;
|
||||||
import com.android.layoutlib.bridge.BridgeConstants;
|
|
||||||
import com.android.layoutlib.bridge.android.BridgeContext;
|
import com.android.layoutlib.bridge.android.BridgeContext;
|
||||||
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
|
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
|
||||||
import com.android.layoutlib.bridge.impl.ParserFactory;
|
import com.android.layoutlib.bridge.impl.ParserFactory;
|
||||||
@@ -142,16 +141,8 @@ public final class BridgeTypedArray extends TypedArray {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public CharSequence getText(int index) {
|
public CharSequence getText(int index) {
|
||||||
if (index < 0 || index >= mResourceData.length) {
|
// FIXME: handle styled strings!
|
||||||
return null;
|
return getString(index);
|
||||||
}
|
|
||||||
|
|
||||||
if (mResourceData[index] != null) {
|
|
||||||
// FIXME: handle styled strings!
|
|
||||||
return mResourceData[index].getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -164,15 +155,14 @@ public final class BridgeTypedArray extends TypedArray {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getString(int index) {
|
public String getString(int index) {
|
||||||
if (index < 0 || index >= mResourceData.length) {
|
if (!hasValue(index)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// As unfortunate as it is, it's possible to use enums with all attribute formats,
|
||||||
if (mResourceData[index] != null) {
|
// not just integers/enums. So, we need to search the enums always. In case,
|
||||||
return mResourceData[index].getValue();
|
// enums are used, the returned value is an integer.
|
||||||
}
|
Integer v = resolveEnumAttribute(index);
|
||||||
|
return v == null ? mResourceData[index].getValue() : String.valueOf((int) v);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -185,20 +175,9 @@ public final class BridgeTypedArray extends TypedArray {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean getBoolean(int index, boolean defValue) {
|
public boolean getBoolean(int index, boolean defValue) {
|
||||||
if (index < 0 || index >= mResourceData.length) {
|
String s = getString(index);
|
||||||
return defValue;
|
return s == null ? defValue : XmlUtils.convertValueToBoolean(s, defValue);
|
||||||
}
|
|
||||||
|
|
||||||
if (mResourceData[index] == null) {
|
|
||||||
return defValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String s = mResourceData[index].getValue();
|
|
||||||
if (s != null) {
|
|
||||||
return XmlUtils.convertValueToBoolean(s, defValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return defValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -211,75 +190,18 @@ public final class BridgeTypedArray extends TypedArray {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getInt(int index, int defValue) {
|
public int getInt(int index, int defValue) {
|
||||||
if (index < 0 || index >= mResourceData.length) {
|
String s = getString(index);
|
||||||
return defValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mResourceData[index] == null) {
|
|
||||||
return defValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String s = mResourceData[index].getValue();
|
|
||||||
|
|
||||||
if (s == null || s.length() == 0) {
|
|
||||||
return defValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return XmlUtils.convertValueToInt(s, defValue);
|
if (s != null) {
|
||||||
|
return XmlUtils.convertValueToInt(s, defValue);
|
||||||
|
}
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
// pass
|
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
|
||||||
|
String.format("\"%s\" in attribute \"%2$s\" is not a valid integer",
|
||||||
|
s, mNames[index]),
|
||||||
|
null);
|
||||||
|
return defValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Field is not null and is not an integer.
|
|
||||||
// Check for possible constants and try to find them.
|
|
||||||
return (int) resolveEnumAttribute(index, defValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Searches for the string in the attributes (flag or enums) and returns the integer.
|
|
||||||
* If found, it will return an integer matching the value. However, if the value is not found,
|
|
||||||
* it returns {@code defValue} which may be a float.
|
|
||||||
*
|
|
||||||
* @param index Index of attribute to retrieve.
|
|
||||||
* @param defValue Value to return if the attribute is not found.
|
|
||||||
*
|
|
||||||
* @return Attribute int value, or defValue if not defined.
|
|
||||||
*/
|
|
||||||
private float resolveEnumAttribute(int index, float defValue) {
|
|
||||||
// Get the map of attribute-constant -> IntegerValue
|
|
||||||
Map<String, Integer> map = null;
|
|
||||||
if (mIsFramework[index]) {
|
|
||||||
map = Bridge.getEnumValues(mNames[index]);
|
|
||||||
} else {
|
|
||||||
// get the styleable matching the resolved name
|
|
||||||
RenderResources res = mContext.getRenderResources();
|
|
||||||
ResourceValue attr = res.getProjectResource(ResourceType.ATTR, mNames[index]);
|
|
||||||
if (attr instanceof AttrResourceValue) {
|
|
||||||
map = ((AttrResourceValue) attr).getAttributeValues();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (map != null) {
|
|
||||||
// accumulator to store the value of the 1+ constants.
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
// split the value in case this is a mix of several flags.
|
|
||||||
String[] keywords = mResourceData[index].getValue().split("\\|");
|
|
||||||
for (String keyword : keywords) {
|
|
||||||
Integer i = map.get(keyword.trim());
|
|
||||||
if (i != null) {
|
|
||||||
result |= i;
|
|
||||||
} else {
|
|
||||||
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
|
|
||||||
String.format(
|
|
||||||
"\"%s\" in attribute \"%2$s\" is not a valid value",
|
|
||||||
keyword, mNames[index]), null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return defValue;
|
return defValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,27 +214,16 @@ public final class BridgeTypedArray extends TypedArray {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public float getFloat(int index, float defValue) {
|
public float getFloat(int index, float defValue) {
|
||||||
if (index < 0 || index >= mResourceData.length) {
|
String s = getString(index);
|
||||||
return defValue;
|
try {
|
||||||
}
|
if (s != null) {
|
||||||
|
return Float.parseFloat(s);
|
||||||
if (mResourceData[index] == null) {
|
|
||||||
return defValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String s = mResourceData[index].getValue();
|
|
||||||
|
|
||||||
if (s != null) {
|
|
||||||
try {
|
|
||||||
return Float.parseFloat(s);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
|
|
||||||
String.format(
|
|
||||||
"\"%s\" in attribute \"%2$s\" cannot be converted to float.",
|
|
||||||
s, mNames[index]), null);
|
|
||||||
|
|
||||||
// we'll return the default value below.
|
|
||||||
}
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
|
||||||
|
String.format("\"%s\" in attribute \"%2$s\" cannot be converted to float.",
|
||||||
|
s, mNames[index]),
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
return defValue;
|
return defValue;
|
||||||
}
|
}
|
||||||
@@ -359,11 +270,7 @@ public final class BridgeTypedArray extends TypedArray {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ColorStateList getColorStateList(int index) {
|
public ColorStateList getColorStateList(int index) {
|
||||||
if (index < 0 || index >= mResourceData.length) {
|
if (!hasValue(index)) {
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mResourceData[index] == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,27 +350,25 @@ public final class BridgeTypedArray extends TypedArray {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public float getDimension(int index, float defValue) {
|
public float getDimension(int index, float defValue) {
|
||||||
if (index < 0 || index >= mResourceData.length) {
|
String s = getString(index);
|
||||||
return defValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mResourceData[index] == null) {
|
|
||||||
return defValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String s = mResourceData[index].getValue();
|
|
||||||
|
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
return defValue;
|
return defValue;
|
||||||
}
|
}
|
||||||
|
// Check if the value is a magic constant that doesn't require a unit.
|
||||||
|
try {
|
||||||
|
int i = Integer.parseInt(s);
|
||||||
|
if (i == LayoutParams.MATCH_PARENT || i == LayoutParams.WRAP_CONTENT) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
|
||||||
if (ResourceHelper.parseFloatAttribute(mNames[index], s, mValue, true)) {
|
if (ResourceHelper.parseFloatAttribute(mNames[index], s, mValue, true)) {
|
||||||
return mValue.getDimension(mBridgeResources.getDisplayMetrics());
|
return mValue.getDimension(mBridgeResources.getDisplayMetrics());
|
||||||
}
|
}
|
||||||
|
|
||||||
// looks like we were unable to resolve the dimension value. Check if it is an attribute
|
return defValue;
|
||||||
// constant.
|
|
||||||
return resolveEnumAttribute(index, defValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -511,16 +416,13 @@ public final class BridgeTypedArray extends TypedArray {
|
|||||||
try {
|
try {
|
||||||
return getDimension(index);
|
return getDimension(index);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
if (mResourceData[index] != null) {
|
String s = getString(index);
|
||||||
String s = mResourceData[index].getValue();
|
|
||||||
|
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
// looks like we were unable to resolve the dimension value
|
// looks like we were unable to resolve the dimension value
|
||||||
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
|
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
|
||||||
String.format(
|
String.format("\"%1$s\" in attribute \"%2$s\" is not a valid format.",
|
||||||
"\"%1$s\" in attribute \"%2$s\" is not a valid format.",
|
|
||||||
s, mNames[index]), null);
|
s, mNames[index]), null);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return defValue;
|
return defValue;
|
||||||
@@ -563,21 +465,19 @@ public final class BridgeTypedArray extends TypedArray {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int getDimension(int index) {
|
private int getDimension(int index) {
|
||||||
if (mResourceData[index] == null) {
|
String s = getString(index);
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
String s = mResourceData[index].getValue();
|
|
||||||
|
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
} else if (s.equals(BridgeConstants.MATCH_PARENT) ||
|
|
||||||
s.equals(BridgeConstants.FILL_PARENT)) {
|
|
||||||
return LayoutParams.MATCH_PARENT;
|
|
||||||
} else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
|
|
||||||
return LayoutParams.WRAP_CONTENT;
|
|
||||||
}
|
}
|
||||||
|
// Check if the value is a magic constant that doesn't require a unit.
|
||||||
|
try {
|
||||||
|
int i = Integer.parseInt(s);
|
||||||
|
if (i == LayoutParams.MATCH_PARENT || i == LayoutParams.WRAP_CONTENT) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
if (ResourceHelper.parseFloatAttribute(mNames[index], s, mValue, true)) {
|
if (ResourceHelper.parseFloatAttribute(mNames[index], s, mValue, true)) {
|
||||||
float f = mValue.getDimension(mBridgeResources.getDisplayMetrics());
|
float f = mValue.getDimension(mBridgeResources.getDisplayMetrics());
|
||||||
|
|
||||||
@@ -607,15 +507,7 @@ public final class BridgeTypedArray extends TypedArray {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public float getFraction(int index, int base, int pbase, float defValue) {
|
public float getFraction(int index, int base, int pbase, float defValue) {
|
||||||
if (index < 0 || index >= mResourceData.length) {
|
String value = getString(index);
|
||||||
return defValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mResourceData[index] == null) {
|
|
||||||
return defValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String value = mResourceData[index].getValue();
|
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return defValue;
|
return defValue;
|
||||||
}
|
}
|
||||||
@@ -766,20 +658,11 @@ public final class BridgeTypedArray extends TypedArray {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Drawable getDrawable(int index) {
|
public Drawable getDrawable(int index) {
|
||||||
if (index < 0 || index >= mResourceData.length) {
|
if (!hasValue(index)) {
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mResourceData[index] == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceValue value = mResourceData[index];
|
ResourceValue value = mResourceData[index];
|
||||||
String stringValue = value.getValue();
|
|
||||||
if (stringValue == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResourceHelper.getDrawable(value, mContext);
|
return ResourceHelper.getDrawable(value, mContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -796,15 +679,7 @@ public final class BridgeTypedArray extends TypedArray {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public CharSequence[] getTextArray(int index) {
|
public CharSequence[] getTextArray(int index) {
|
||||||
if (index < 0 || index >= mResourceData.length) {
|
String value = getString(index);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mResourceData[index] == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String value = mResourceData[index].getValue();
|
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
return new CharSequence[] { value };
|
return new CharSequence[] { value };
|
||||||
}
|
}
|
||||||
@@ -837,17 +712,8 @@ public final class BridgeTypedArray extends TypedArray {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean getValue(int index, TypedValue outValue) {
|
public boolean getValue(int index, TypedValue outValue) {
|
||||||
if (index < 0 || index >= mResourceData.length) {
|
String s = getString(index);
|
||||||
return false;
|
return s != null && ResourceHelper.parseFloatAttribute(mNames[index], s, outValue, false);
|
||||||
}
|
|
||||||
|
|
||||||
if (mResourceData[index] == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String s = mResourceData[index].getValue();
|
|
||||||
|
|
||||||
return ResourceHelper.parseFloatAttribute(mNames[index], s, outValue, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -859,12 +725,7 @@ public final class BridgeTypedArray extends TypedArray {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean hasValue(int index) {
|
public boolean hasValue(int index) {
|
||||||
//noinspection SimplifiableIfStatement
|
return index >= 0 && index < mResourceData.length && mResourceData[index] != null;
|
||||||
if (index < 0 || index >= mResourceData.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mResourceData[index] != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -912,6 +773,52 @@ public final class BridgeTypedArray extends TypedArray {
|
|||||||
return Arrays.toString(mResourceData);
|
return Arrays.toString(mResourceData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for the string in the attributes (flag or enums) and returns the integer.
|
||||||
|
* If found, it will return an integer matching the value.
|
||||||
|
*
|
||||||
|
* @param index Index of attribute to retrieve.
|
||||||
|
*
|
||||||
|
* @return Attribute int value, or null if not defined.
|
||||||
|
*/
|
||||||
|
private Integer resolveEnumAttribute(int index) {
|
||||||
|
// Get the map of attribute-constant -> IntegerValue
|
||||||
|
Map<String, Integer> map = null;
|
||||||
|
if (mIsFramework[index]) {
|
||||||
|
map = Bridge.getEnumValues(mNames[index]);
|
||||||
|
} else {
|
||||||
|
// get the styleable matching the resolved name
|
||||||
|
RenderResources res = mContext.getRenderResources();
|
||||||
|
ResourceValue attr = res.getProjectResource(ResourceType.ATTR, mNames[index]);
|
||||||
|
if (attr instanceof AttrResourceValue) {
|
||||||
|
map = ((AttrResourceValue) attr).getAttributeValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map != null) {
|
||||||
|
// accumulator to store the value of the 1+ constants.
|
||||||
|
int result = 0;
|
||||||
|
boolean found = false;
|
||||||
|
|
||||||
|
// split the value in case this is a mix of several flags.
|
||||||
|
String[] keywords = mResourceData[index].getValue().split("\\|");
|
||||||
|
for (String keyword : keywords) {
|
||||||
|
Integer i = map.get(keyword.trim());
|
||||||
|
if (i != null) {
|
||||||
|
result |= i;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
// TODO: We should act smartly and log a warning for incorrect keywords. However,
|
||||||
|
// this method is currently called even if the resourceValue is not an enum.
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
static TypedArray obtain(Resources res, int len) {
|
static TypedArray obtain(Resources res, int len) {
|
||||||
return res instanceof BridgeResources ?
|
return res instanceof BridgeResources ?
|
||||||
new BridgeTypedArray(((BridgeResources) res), null, len, true) : null;
|
new BridgeTypedArray(((BridgeResources) res), null, len, true) : null;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.layoutlib.bridge.impl;
|
package com.android.layoutlib.bridge.impl;
|
||||||
|
|
||||||
|
import com.android.annotations.NonNull;
|
||||||
import com.android.ide.common.rendering.api.DensityBasedResourceValue;
|
import com.android.ide.common.rendering.api.DensityBasedResourceValue;
|
||||||
import com.android.ide.common.rendering.api.LayoutLog;
|
import com.android.ide.common.rendering.api.LayoutLog;
|
||||||
import com.android.ide.common.rendering.api.RenderResources;
|
import com.android.ide.common.rendering.api.RenderResources;
|
||||||
@@ -358,7 +359,7 @@ public final class ResourceHelper {
|
|||||||
* @param requireUnit whether the value is expected to contain a unit.
|
* @param requireUnit whether the value is expected to contain a unit.
|
||||||
* @return true if success.
|
* @return true if success.
|
||||||
*/
|
*/
|
||||||
public static boolean parseFloatAttribute(String attribute, String value,
|
public static boolean parseFloatAttribute(String attribute, @NonNull String value,
|
||||||
TypedValue outValue, boolean requireUnit) {
|
TypedValue outValue, boolean requireUnit) {
|
||||||
assert !requireUnit || attribute != null;
|
assert !requireUnit || attribute != null;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user