Search in sources :

Example 1 with AttributeResource

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;
    }
}
Also used : AttributeResource(org.robolectric.res.AttributeResource) EmptyStyle(org.robolectric.res.EmptyStyle) Style(org.robolectric.res.Style) ResName(org.robolectric.res.ResName) TypedValue(android.util.TypedValue)

Example 2 with AttributeResource

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);
}
Also used : AttributeResource(org.robolectric.res.AttributeResource) ResName(org.robolectric.res.ResName)

Example 3 with AttributeResource

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;
}
Also used : AttributeResource(org.robolectric.res.AttributeResource) ThemeStyleSet(org.robolectric.res.ThemeStyleSet) ResName(org.robolectric.res.ResName) HiddenApi(org.robolectric.annotation.HiddenApi) Implementation(org.robolectric.annotation.Implementation)

Example 4 with AttributeResource

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);
    }
}
Also used : AttrData(org.robolectric.res.AttrData) FileTypedResource(org.robolectric.res.FileTypedResource) TypedResource(org.robolectric.res.TypedResource) ResType(org.robolectric.res.ResType) AttributeResource(org.robolectric.res.AttributeResource) ResName(org.robolectric.res.ResName) Resources(android.content.res.Resources)

Aggregations

AttributeResource (org.robolectric.res.AttributeResource)4 ResName (org.robolectric.res.ResName)4 Resources (android.content.res.Resources)1 TypedValue (android.util.TypedValue)1 HiddenApi (org.robolectric.annotation.HiddenApi)1 Implementation (org.robolectric.annotation.Implementation)1 AttrData (org.robolectric.res.AttrData)1 EmptyStyle (org.robolectric.res.EmptyStyle)1 FileTypedResource (org.robolectric.res.FileTypedResource)1 ResType (org.robolectric.res.ResType)1 Style (org.robolectric.res.Style)1 ThemeStyleSet (org.robolectric.res.ThemeStyleSet)1 TypedResource (org.robolectric.res.TypedResource)1