BridgeTypedArraypublic final class BridgeTypedArray extends TypedArray Custom implementation of TypedArray to handle non compiled resources. |
Fields Summary |
---|
private final BridgeResources | mBridgeResources | private final com.android.layoutlib.bridge.android.BridgeContext | mContext | private final boolean | mPlatformFile | private final com.android.ide.common.rendering.api.ResourceValue[] | mResourceData | private final String[] | mNames | private final boolean[] | mIsFramework |
Methods Summary |
---|
public void | bridgeSetValue(int index, java.lang.String name, boolean isFramework, com.android.ide.common.rendering.api.ResourceValue value)A bridge-specific method that sets a value in the type array
mResourceData[index] = value;
mNames[index] = name;
mIsFramework[index] = isFramework;
| public int[] | extractThemeAttrs()
// The drawables are always inflated with a Theme and we don't care about caching. So,
// just return.
return null;
| public boolean | getBoolean(int index, boolean defValue)Retrieve the boolean value for the attribute at index.
String s = getString(index);
return s == null ? defValue : XmlUtils.convertValueToBoolean(s, defValue);
| public int | getChangingConfigurations()
// We don't care about caching. Any change in configuration is a fresh render. So,
// just return.
return 0;
| public int | getColor(int index, int defValue)Retrieve the color value for the attribute at index. If
the attribute references a color resource holding a complex
{@link android.content.res.ColorStateList}, then the default color from
the set is returned.
if (index < 0 || index >= mResourceData.length) {
return defValue;
}
if (mResourceData[index] == null) {
return defValue;
}
ColorStateList colorStateList = ResourceHelper.getColorStateList(
mResourceData[index], mContext);
if (colorStateList != null) {
return colorStateList.getDefaultColor();
}
return defValue;
| public ColorStateList | getColorStateList(int index)Retrieve the ColorStateList for the attribute at index.
The value may be either a single solid color or a reference to
a color or complex {@link android.content.res.ColorStateList} description.
if (!hasValue(index)) {
return null;
}
ResourceValue resValue = mResourceData[index];
String value = resValue.getValue();
if (value == null) {
return null;
}
// let the framework inflate the ColorStateList from the XML file.
File f = new File(value);
if (f.isFile()) {
try {
XmlPullParser parser = ParserFactory.create(f);
BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
parser, mContext, resValue.isFramework());
try {
return ColorStateList.createFromXml(mContext.getResources(), blockParser);
} finally {
blockParser.ensurePopped();
}
} catch (XmlPullParserException e) {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
"Failed to configure parser for " + value, e, null);
return null;
} catch (Exception e) {
// this is an error and not warning since the file existence is checked before
// attempting to parse it.
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
"Failed to parse file " + value, e, null);
return null;
}
}
try {
int color = ResourceHelper.getColor(value);
return ColorStateList.valueOf(color);
} catch (NumberFormatException e) {
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e, null);
}
return null;
| public float | getDimension(int index, float defValue)Retrieve a dimensional unit attribute at index. Unit
conversions are based on the current {@link DisplayMetrics}
associated with the resources this {@link TypedArray} object
came from.
String s = getString(index);
if (s == null) {
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)) {
return mValue.getDimension(mBridgeResources.getDisplayMetrics());
}
return defValue;
| private int | getDimension(int index)
String s = getString(index);
if (s == null) {
throw new RuntimeException();
}
// 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)) {
float f = mValue.getDimension(mBridgeResources.getDisplayMetrics());
final int res = (int)(f+0.5f);
if (res != 0) return res;
if (f == 0) return 0;
if (f > 0) return 1;
}
throw new RuntimeException();
| public int | getDimensionPixelOffset(int index, int defValue)Retrieve a dimensional unit attribute at index for use
as an offset in raw pixels. This is the same as
{@link #getDimension}, except the returned value is converted to
integer pixels for you. An offset conversion involves simply
truncating the base value to an integer.
return (int) getDimension(index, defValue);
| public int | getDimensionPixelSize(int index, int defValue)Retrieve a dimensional unit attribute at index for use
as a size in raw pixels. This is the same as
{@link #getDimension}, except the returned value is converted to
integer pixels for use as a size. A size conversion involves
rounding the base value, and ensuring that a non-zero base value
is at least one pixel in size.
try {
return getDimension(index);
} catch (RuntimeException e) {
String s = getString(index);
if (s != null) {
// looks like we were unable to resolve the dimension value
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
String.format("\"%1$s\" in attribute \"%2$s\" is not a valid format.",
s, mNames[index]), null);
}
return defValue;
}
| public android.graphics.drawable.Drawable | getDrawable(int index)Retrieve the Drawable for the attribute at index. This
gets the resource ID of the selected attribute, and uses
{@link Resources#getDrawable Resources.getDrawable} of the owning
Resources object to retrieve its Drawable.
if (!hasValue(index)) {
return null;
}
ResourceValue value = mResourceData[index];
return ResourceHelper.getDrawable(value, mContext, mTheme);
| public float | getFloat(int index, float defValue)Retrieve the float value for the attribute at index.
String s = getString(index);
try {
if (s != null) {
return Float.parseFloat(s);
}
} catch (NumberFormatException e) {
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
String.format("\"%1$s\" in attribute \"%2$s\" cannot be converted to float.",
s, mNames[index]),
null);
}
return defValue;
| public float | getFraction(int index, int base, int pbase, float defValue)Retrieve a fractional unit attribute at index.
String value = getString(index);
if (value == null) {
return defValue;
}
if (ResourceHelper.parseFloatAttribute(mNames[index], value, mValue, false)) {
return mValue.getFraction(base, pbase);
}
// looks like we were unable to resolve the fraction value
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
String.format(
"\"%1$s\" in attribute \"%2$s\" cannot be converted to a fraction.",
value, mNames[index]), null);
return defValue;
| public int | getInt(int index, int defValue)Retrieve the integer value for the attribute at index.
String s = getString(index);
try {
if (s != null) {
return XmlUtils.convertValueToInt(s, defValue);
}
} catch (NumberFormatException e) {
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
String.format("\"%1$s\" in attribute \"%2$s\" is not a valid integer",
s, mNames[index]),
null);
return defValue;
}
return defValue;
| public int | getInteger(int index, int defValue)Retrieve the integer value for the attribute at index.
return getInt(index, defValue);
| public int | getLayoutDimension(int index, java.lang.String name)Special version of {@link #getDimensionPixelSize} for retrieving
{@link android.view.ViewGroup}'s layout_width and layout_height
attributes. This is only here for performance reasons; applications
should use {@link #getDimensionPixelSize}.
try {
// this will throw an exception
return getDimension(index);
} catch (RuntimeException e) {
if (LayoutInflater_Delegate.sIsInInclude) {
throw new RuntimeException();
}
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
"You must supply a " + name + " attribute.", null);
return 0;
}
| public int | getLayoutDimension(int index, int defValue)
return getDimensionPixelSize(index, defValue);
| public java.lang.String | getPositionDescription()Returns a message about the parser state suitable for printing error messages.
return "<internal -- stub if needed>";
| public int | getResourceId(int index, int defValue)Retrieve the resource identifier for the attribute at
index. Note that attribute resource as resolved when
the overall {@link TypedArray} object is retrieved. As a
result, this function will return the resource identifier of the
final resource value that was found, not necessarily the
original resource that was specified by the attribute.
if (index < 0 || index >= mResourceData.length) {
return defValue;
}
// get the Resource for this index
ResourceValue resValue = mResourceData[index];
// no data, return the default value.
if (resValue == null) {
return defValue;
}
// check if this is a style resource
if (resValue instanceof StyleResourceValue) {
// get the id that will represent this style.
return mContext.getDynamicIdByStyle((StyleResourceValue)resValue);
}
// if the attribute was a reference to a resource, and not a declaration of an id (@+id),
// then the xml attribute value was "resolved" which leads us to a ResourceValue with a
// valid getType() and getName() returning a resource name.
// (and getValue() returning null!). We need to handle this!
if (resValue.getResourceType() != null) {
// if this is a framework id
if (mPlatformFile || resValue.isFramework()) {
// look for idName in the android R classes
return mContext.getFrameworkResourceValue(
resValue.getResourceType(), resValue.getName(), defValue);
}
// look for idName in the project R class.
return mContext.getProjectResourceValue(
resValue.getResourceType(), resValue.getName(), defValue);
}
// else, try to get the value, and resolve it somehow.
String value = resValue.getValue();
if (value == null) {
return defValue;
}
// if the value is just an integer, return it.
try {
int i = Integer.parseInt(value);
if (Integer.toString(i).equals(value)) {
return i;
}
} catch (NumberFormatException e) {
// pass
}
// Handle the @id/<name>, @+id/<name> and @android:id/<name>
// We need to return the exact value that was compiled (from the various R classes),
// as these values can be reused internally with calls to findViewById().
// There's a trick with platform layouts that not use "android:" but their IDs are in
// fact in the android.R and com.android.internal.R classes.
// The field mPlatformFile will indicate that all IDs are to be looked up in the android R
// classes exclusively.
// if this is a reference to an id, find it.
if (value.startsWith("@id/") || value.startsWith("@+") ||
value.startsWith("@android:id/")) {
int pos = value.indexOf('/");
String idName = value.substring(pos + 1);
boolean create = value.startsWith("@+");
boolean isFrameworkId =
mPlatformFile || value.startsWith("@android") || value.startsWith("@+android");
// Look for the idName in project or android R class depending on isPlatform.
if (create) {
Integer idValue;
if (isFrameworkId) {
idValue = Bridge.getResourceId(ResourceType.ID, idName);
} else {
idValue = mContext.getProjectCallback().getResourceId(ResourceType.ID, idName);
}
return idValue == null ? defValue : idValue;
}
// This calls the same method as in if(create), but doesn't create a dynamic id, if
// one is not found.
if (isFrameworkId) {
return mContext.getFrameworkResourceValue(ResourceType.ID, idName, defValue);
} else {
return mContext.getProjectResourceValue(ResourceType.ID, idName, defValue);
}
}
// not a direct id valid reference? resolve it
Integer idValue;
if (resValue.isFramework()) {
idValue = Bridge.getResourceId(resValue.getResourceType(),
resValue.getName());
} else {
idValue = mContext.getProjectCallback().getResourceId(
resValue.getResourceType(), resValue.getName());
}
if (idValue != null) {
return idValue;
}
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_RESOLVE,
String.format(
"Unable to resolve id \"%1$s\" for attribute \"%2$s\"", value, mNames[index]),
resValue);
return defValue;
| public Resources | getResources()Return the Resources object this array was loaded from.
return mBridgeResources;
| public java.lang.String | getString(int index)Retrieve the string value for the attribute at index.
if (!hasValue(index)) {
return null;
}
// As unfortunate as it is, it's possible to use enums with all attribute formats,
// not just integers/enums. So, we need to search the enums always. In case
// enums are used, the returned value is an integer.
Integer v = resolveEnumAttribute(index);
return v == null ? mResourceData[index].getValue() : String.valueOf((int) v);
| public java.lang.CharSequence | getText(int index)Retrieve the styled string value for the attribute at index.
// FIXME: handle styled strings!
return getString(index);
| public java.lang.CharSequence[] | getTextArray(int index)Retrieve the CharSequence[] for the attribute at index.
This gets the resource ID of the selected attribute, and uses
{@link Resources#getTextArray Resources.getTextArray} of the owning
Resources object to retrieve its String[].
String value = getString(index);
if (value != null) {
return new CharSequence[] { value };
}
return null;
| public int | getThemeAttributeId(int index, int defValue)
// TODO: Get the right Theme Attribute ID to enable caching of the drawables.
return defValue;
| public boolean | getValue(int index, android.util.TypedValue outValue)Retrieve the raw TypedValue for the attribute at index.
String s = getString(index);
return s != null && ResourceHelper.parseFloatAttribute(mNames[index], s, outValue, false);
| public boolean | hasValue(int index)Determines whether there is an attribute at index.
return index >= 0 && index < mResourceData.length && mResourceData[index] != null;
| public int | length()Return the number of values in this array.
return mResourceData.length;
| static TypedArray | obtain(Resources res, int len)
return res instanceof BridgeResources ?
new BridgeTypedArray(((BridgeResources) res), null, len, true) : null;
| public android.util.TypedValue | peekValue(int index)Retrieve the raw TypedValue for the attribute at index
and return a temporary object holding its data. This object is only
valid until the next call on to {@link TypedArray}.
if (index < 0 || index >= mResourceData.length) {
return null;
}
if (getValue(index, mValue)) {
return mValue;
}
return null;
| public void | recycle()Give back a previously retrieved TypedArray, for later re-use.
// pass
| private java.lang.Integer | resolveEnumAttribute(int index)Searches for the string in the attributes (flag or enums) and returns the integer.
If found, it will return an integer matching the value.
// 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;
| public void | sealArray()Seals the array after all calls to
{@link #bridgeSetValue(int, String, boolean, ResourceValue)} have been done.
This allows to compute the list of non default values, permitting
{@link #getIndexCount()} to return the proper value.
// fills TypedArray.mIndices which is used to implement getIndexCount/getIndexAt
// first count the array size
int count = 0;
for (int i = 0; i < mResourceData.length; i++) {
ResourceValue data = mResourceData[i];
if (data != null) {
if (RenderResources.REFERENCE_NULL.equals(data.getValue())) {
// No need to store this resource value. This saves needless checking for
// "@null" every time an attribute is requested.
mResourceData[i] = null;
} else {
count++;
}
}
}
// allocate the table with an extra to store the size
mIndices = new int[count+1];
mIndices[0] = count;
// fill the array with the indices.
int index = 1;
for (int i = 0 ; i < mResourceData.length ; i++) {
if (mResourceData[i] != null) {
mIndices[index++] = i;
}
}
| public void | setTheme(android.content.res.Resources.Theme theme)Set the theme to be used for inflating drawables.
mTheme = theme;
| public java.lang.String | toString()
return Arrays.toString(mResourceData);
|
|