use of org.robolectric.res.AttributeResource in project robolectric by robolectric.
the class ShadowAssetManager method buildTypedValue.
private TypedValue buildTypedValue(AttributeSet set, int resId, int defStyleAttr, Style themeStyleSet, int defStyleRes) {
/*
* When determining the final value of a particular attribute, there are four inputs that come into play:
*
* 1. Any attribute values in the given AttributeSet.
* 2. The style resource specified in the AttributeSet (named "style").
* 3. The default style specified by defStyleAttr and defStyleRes
* 4. The base values in this theme.
*/
Style defStyleFromAttr = null;
Style defStyleFromRes = null;
Style styleAttrStyle = null;
if (defStyleAttr != 0) {
// Load the theme attribute for the default style attributes. E.g., attr/buttonStyle
ResName defStyleName = getResName(defStyleAttr);
// Load the style for the default style attribute. E.g. "@style/Widget.Robolectric.Button";
AttributeResource defStyleAttribute = themeStyleSet.getAttrValue(defStyleName);
if (defStyleAttribute != null) {
while (defStyleAttribute.isStyleReference()) {
AttributeResource other = themeStyleSet.getAttrValue(defStyleAttribute.getStyleReference());
if (other == null) {
throw new RuntimeException("couldn't dereference " + defStyleAttribute);
}
defStyleAttribute = other;
}
if (defStyleAttribute.isResourceReference()) {
ResName defStyleResName = defStyleAttribute.getResourceReference();
defStyleFromAttr = resolveStyle(defStyleResName, themeStyleSet);
}
}
}
if (set != null && set.getStyleAttribute() != 0) {
ResName styleAttributeResName = getResName(set.getStyleAttribute());
while (styleAttributeResName.type.equals("attr")) {
AttributeResource attrValue = themeStyleSet.getAttrValue(styleAttributeResName);
if (attrValue == null) {
throw new RuntimeException("no value for " + styleAttributeResName.getFullyQualifiedName() + " in " + themeStyleSet);
}
if (attrValue.isResourceReference()) {
styleAttributeResName = attrValue.getResourceReference();
} else if (attrValue.isStyleReference()) {
styleAttributeResName = attrValue.getStyleReference();
}
}
styleAttrStyle = resolveStyle(styleAttributeResName, themeStyleSet);
}
if (defStyleRes != 0) {
ResName resName = getResName(defStyleRes);
if (resName.type.equals("attr")) {
AttributeResource attributeValue = findAttributeValue(defStyleRes, set, styleAttrStyle, defStyleFromAttr, defStyleFromAttr, themeStyleSet);
if (attributeValue != null) {
if (attributeValue.isStyleReference()) {
resName = themeStyleSet.getAttrValue(attributeValue.getStyleReference()).getResourceReference();
} else if (attributeValue.isResourceReference()) {
resName = attributeValue.getResourceReference();
}
}
}
defStyleFromRes = resolveStyle(resName, themeStyleSet);
}
AttributeResource attribute = findAttributeValue(resId, set, styleAttrStyle, defStyleFromAttr, defStyleFromRes, themeStyleSet);
while (attribute != null && attribute.isStyleReference()) {
ResName otherAttrName = attribute.getStyleReference();
if (attribute.resName.equals(otherAttrName)) {
Logger.info("huh... circular reference for %s?", attribute.resName.getFullyQualifiedName());
return null;
}
ResName resName = resourceTable.getResName(resId);
AttributeResource otherAttr = themeStyleSet.getAttrValue(otherAttrName);
if (otherAttr == null) {
strictError("no such attr %s in %s while resolving value for %s", attribute.value, themeStyleSet, resName.getFullyQualifiedName());
attribute = null;
} else {
attribute = new AttributeResource(resName, otherAttr.value, otherAttr.contextPackageName);
}
}
if (attribute == null || attribute.isNull()) {
return null;
} else {
TypedValue typedValue = new TypedValue();
convertAndFill(attribute, typedValue, RuntimeEnvironment.getQualifiers(), true);
return typedValue;
}
}
use of org.robolectric.res.AttributeResource in project robolectric by robolectric.
the class ShadowAssetManager method findAttributeValue.
private AttributeResource findAttributeValue(int resId, AttributeSet attributeSet, Style styleAttrStyle, Style defStyleFromAttr, Style defStyleFromRes, @NotNull Style themeStyleSet) {
if (attributeSet != null) {
for (int i = 0; i < attributeSet.getAttributeCount(); i++) {
if (attributeSet.getAttributeNameResource(i) == resId && attributeSet.getAttributeValue(i) != null) {
String defaultPackageName = ResourceIds.isFrameworkResource(resId) ? "android" : RuntimeEnvironment.application.getPackageName();
ResName resName = ResName.qualifyResName(attributeSet.getAttributeName(i), defaultPackageName, "attr");
Integer referenceResId = null;
if (AttributeResource.isResourceReference(attributeSet.getAttributeValue(i))) {
referenceResId = attributeSet.getAttributeResourceValue(i, -1);
}
return new AttributeResource(resName, attributeSet.getAttributeValue(i), "fixme!!!", referenceResId);
}
}
}
ResName attrName = resourceTable.getResName(resId);
if (attrName == null)
return null;
if (styleAttrStyle != null) {
AttributeResource attribute = styleAttrStyle.getAttrValue(attrName);
if (attribute != null) {
return attribute;
}
}
// else if attr in defStyleFromAttr, use its value
if (defStyleFromAttr != null) {
AttributeResource attribute = defStyleFromAttr.getAttrValue(attrName);
if (attribute != null) {
return attribute;
}
}
if (defStyleFromRes != null) {
AttributeResource attribute = defStyleFromRes.getAttrValue(attrName);
if (attribute != null) {
return attribute;
}
}
// else if attr in theme, use its value
return themeStyleSet.getAttrValue(attrName);
}
use of org.robolectric.res.AttributeResource in project robolectric by robolectric.
the class ShadowAssetManager method getThemeValue.
@HiddenApi
@Implementation(minSdk = LOLLIPOP)
public boolean getThemeValue(long themePtr, int ident, TypedValue outValue, boolean resolveRefs) {
ResName resName = resourceTable.getResName(ident);
ThemeStyleSet themeStyleSet = getNativeTheme(themePtr).themeStyleSet;
AttributeResource attrValue = themeStyleSet.getAttrValue(resName);
while (attrValue != null && attrValue.isStyleReference()) {
ResName attrResName = attrValue.getStyleReference();
if (attrValue.resName.equals(attrResName)) {
Logger.info("huh... circular reference for %s?", attrResName.getFullyQualifiedName());
return false;
}
attrValue = themeStyleSet.getAttrValue(attrResName);
}
if (attrValue != null) {
convertAndFill(attrValue, outValue, RuntimeEnvironment.getQualifiers(), resolveRefs);
return true;
}
return false;
}
use of org.robolectric.res.AttributeResource in project robolectric by robolectric.
the class ShadowAssetManager method convertAndFill.
private void convertAndFill(AttributeResource attribute, TypedValue outValue, String qualifiers, boolean resolveRefs) {
if (attribute.isNull()) {
outValue.type = TypedValue.TYPE_NULL;
outValue.data = TypedValue.DATA_NULL_UNDEFINED;
return;
} else if (attribute.isEmpty()) {
outValue.type = TypedValue.TYPE_NULL;
outValue.data = TypedValue.DATA_NULL_EMPTY;
return;
}
// short-circuit Android caching of loaded resources cuz our string positions don't remain stable...
outValue.assetCookie = Converter.getNextStringCookie();
// TODO: Handle resource and style references
if (attribute.isStyleReference()) {
return;
}
while (attribute.isResourceReference()) {
Integer resourceId;
ResName resName = attribute.getResourceReference();
if (attribute.getReferenceResId() != null) {
resourceId = attribute.getReferenceResId();
} else {
resourceId = resourceTable.getResourceId(resName);
}
if (resourceId == null) {
throw new Resources.NotFoundException("unknown resource " + resName);
}
outValue.type = TypedValue.TYPE_REFERENCE;
if (!resolveRefs) {
// Just return the resourceId if resolveRefs is false.
outValue.data = resourceId;
return;
}
outValue.resourceId = resourceId;
TypedResource dereferencedRef = resourceTable.getValue(resName, qualifiers);
if (dereferencedRef == null) {
Logger.strict("couldn't resolve %s from %s", resName.getFullyQualifiedName(), attribute);
if (resName.type.equals("id")) {
return;
} else if (resName.type.equals("layout")) {
// resourceId is good enough, right?
return;
} else if (resName.type.equals("dimen")) {
return;
} else if (resName.type.equals("transition")) {
return;
} else if (resName.type.equals("interpolator")) {
return;
} else if (resName.type.equals("menu")) {
return;
} else if (resName.type.equals("raw")) {
return;
} else if (DrawableResourceLoader.isStillHandledHere(resName.type)) {
// wtf. color and drawable references reference are all kinds of stupid.
TypedResource drawableResource = resourceTable.getValue(resName, qualifiers);
if (drawableResource == null) {
throw new Resources.NotFoundException("can't find file for " + resName);
} else {
outValue.type = TypedValue.TYPE_STRING;
outValue.data = 0;
outValue.assetCookie = Converter.getNextStringCookie();
outValue.string = (CharSequence) drawableResource.getData();
return;
}
} else {
throw new RuntimeException("huh? " + resName);
}
} else {
if (dereferencedRef.isFile()) {
outValue.type = TypedValue.TYPE_STRING;
outValue.data = 0;
outValue.assetCookie = Converter.getNextStringCookie();
outValue.string = dereferencedRef.asString();
return;
} else if (dereferencedRef.getData() instanceof String) {
attribute = new AttributeResource(attribute.resName, dereferencedRef.asString(), resName.packageName);
if (attribute.isResourceReference()) {
continue;
}
if (resolveRefs) {
Converter.getConverter(dereferencedRef.getResType()).fillTypedValue(attribute.value, outValue);
return;
}
}
}
break;
}
if (attribute.isNull()) {
outValue.type = TypedValue.TYPE_NULL;
return;
}
TypedResource attrTypeData = resourceTable.getValue(attribute.resName, qualifiers);
if (attrTypeData != null) {
AttrData attrData = (AttrData) attrTypeData.getData();
String format = attrData.getFormat();
String[] types = format.split("\\|");
for (String type : types) {
// already handled above
if ("reference".equals(type))
continue;
Converter converter = Converter.getConverterFor(attrData, type);
if (converter != null) {
if (converter.fillTypedValue(attribute.value, outValue)) {
return;
}
}
}
} else {
/**
* In cases where the runtime framework doesn't know this attribute, e.g: viewportHeight (added in 21) on a
* KitKat runtine, then infer the attribute type from the value.
*
* TODO: When we are able to pass the SDK resources from the build environment then we can remove this
* and replace the NullResourceLoader with simple ResourceProvider that only parses attribute type information.
*/
ResType resType = ResType.inferFromValue(attribute.value);
Converter.getConverter(resType).fillTypedValue(attribute.value, outValue);
}
}
Aggregations