in rendering/src/com/android/tools/rendering/parsers/LayoutRenderPullParser.java [655:775]
public String getAttributeValue(String namespace, String localName) {
// get the current uiNode
TagSnapshot tag = getCurrentNode();
if (tag == null) {
return null;
}
if (ATTR_LAYOUT.equals(localName) && isFragmentTag(tag.tagName)) {
String layout = tag.getAttribute(LayoutMetadata.KEY_FRAGMENT_LAYOUT, TOOLS_URI);
if (layout != null) {
return layout;
}
String navGraph = tag.getAttribute(ATTR_NAV_GRAPH, AUTO_URI);
if (navGraph != null && myNavGraphResolver != null) {
return myNavGraphResolver.resolve(navGraph);
}
}
else if (myUseSrcCompat && ATTR_SRC.equals(localName) && TAGS_SUPPORTING_SRC_COMPAT.contains(tag.tagName)) {
String srcCompatValue = getAttributeValue(AUTO_URI, ATTR_SRC_COMPAT);
if (srcCompatValue != null) {
return srcCompatValue;
}
}
else if (ATTR_PADDING_LEFT.equals(localName) || ATTR_PADDING_RIGHT.equals(localName)) {
String horizontal = getAttributeValue(ANDROID_URI, ATTR_PADDING_HORIZONTAL);
if (horizontal != null) {
return horizontal;
}
}
else if (ATTR_PADDING_TOP.equals(localName) || ATTR_PADDING_BOTTOM.equals(localName)) {
String vertical = getAttributeValue(ANDROID_URI, ATTR_PADDING_VERTICAL);
if (vertical != null) {
return vertical;
}
}
String value = null;
if (namespace == null) {
value = tag.getAttribute(localName);
}
else if (!myUseToolsPositionAndVisibility && namespace.equals(TOOLS_URI)) {
value = null;
}
else if (namespace.equals(ANDROID_URI) || namespace.equals(AUTO_URI)) {
// tools attributes can override both android and app namespace attributes
if (!myHasToolsNamespace || (!myUseToolsPositionAndVisibility && myToolsPositionAndVisibilityAttributes.contains(localName))) {
// tools namespace is not declared
value = tag.getAttribute(localName, namespace);
}
else {
//noinspection ForLoopReplaceableByForEach
for (int i = 0, n = tag.attributes.size(); i < n; i++) {
AttributeSnapshot attribute = tag.attributes.get(i);
if (localName.equals(attribute.name)) {
String attrPrefix = attribute.prefix;
String uri = attrPrefix != null
? myNamespacePrefixToUri.computeIfAbsent(attrPrefix, prefix -> computeUriFromPrefix(myRoot, prefix))
: null;
if (TOOLS_URI.equals(uri)) {
value = attribute.value;
if (value != null && value.isEmpty()) {
// Empty when there is a runtime attribute set means unset the runtime attribute
value = tag.getAttribute(localName, ANDROID_URI) != null ? null : value;
}
break;
}
else if (namespace.equals(attribute.namespace)) {
value = attribute.value;
// Don't break: continue searching in case we find a tools design time attribute
}
}
}
}
}
else {
// The namespace is not android, app or null
if (!TOOLS_URI.equals(namespace)) {
// Auto-convert http://schemas.android.com/apk/res-auto resources. The lookup
// will be for the current application's resource package, e.g.
// http://schemas.android.com/apk/res/foo.bar, but the XML document will
// be using http://schemas.android.com/apk/res-auto in library projects:
//noinspection ForLoopReplaceableByForEach
for (int i = 0, n = tag.attributes.size(); i < n; i++) {
AttributeSnapshot attribute = tag.attributes.get(i);
if (localName.equals(attribute.name) && (namespace.equals(attribute.namespace) ||
AUTO_URI.equals(attribute.namespace))) {
value = attribute.value;
break;
}
}
}
else {
// We are asked specifically to return a tools attribute
value = tag.getAttribute(localName, namespace);
}
}
if (value != null) {
// on the fly convert match_parent to fill_parent for compatibility with older
// platforms.
if (VALUE_MATCH_PARENT.equals(value) &&
(ATTR_LAYOUT_WIDTH.equals(localName) || ATTR_LAYOUT_HEIGHT.equals(localName)) &&
ANDROID_URI.equals(namespace)) {
return VALUE_FILL_PARENT;
}
// Replace all whitespace characters with a standard space
value = value.replaceAll("\\s", " ");
// Handle unicode and XML escapes
for (int i = 0, n = value.length(); i < n; i++) {
char c = value.charAt(i);
if (c == '&' || c == '\\') {
value = ValueXmlHelper.unescapeResourceString(value, true, false);
break;
}
}
}
return value;
}