blob: cc7e52cc39423af49c25b056cf3058b4cba865e7 [file] [log] [blame]
package org.robolectric.manifest;
import android.content.res.Resources;
import org.robolectric.res.ResName;
import org.robolectric.res.ResourceTable;
import org.robolectric.res.TypedResource;
import org.robolectric.shadows.ResourceHelper;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public final class MetaData {
private final Map<String, Object> valueMap = new LinkedHashMap<>();
private final Map<String, VALUE_TYPE> typeMap = new LinkedHashMap<>();
private boolean initialised;
public MetaData(List<Node> nodes) {
for (Node metaNode : nodes) {
NamedNodeMap attributes = metaNode.getAttributes();
Node nameAttr = attributes.getNamedItem("android:name");
Node valueAttr = attributes.getNamedItem("android:value");
Node resourceAttr = attributes.getNamedItem("android:resource");
if (valueAttr != null) {
valueMap.put(nameAttr.getNodeValue(), valueAttr.getNodeValue());
typeMap.put(nameAttr.getNodeValue(), VALUE_TYPE.VALUE);
} else if (resourceAttr != null) {
valueMap.put(nameAttr.getNodeValue(), resourceAttr.getNodeValue());
typeMap.put(nameAttr.getNodeValue(), VALUE_TYPE.RESOURCE);
}
}
}
public void init(ResourceTable resourceTable, String packageName) {
if (!initialised) {
for (Map.Entry<String,VALUE_TYPE> entry : typeMap.entrySet()) {
String value = valueMap.get(entry.getKey()).toString();
if (value.startsWith("@")) {
ResName resName = ResName.qualifyResName(value.substring(1), packageName, null);
switch (entry.getValue()) {
case RESOURCE:
// Was provided by resource attribute, store resource ID
valueMap.put(entry.getKey(), resourceTable.getResourceId(resName));
break;
case VALUE:
// Was provided by value attribute, need to inferFromValue it
TypedResource<?> typedRes = resourceTable.getValue(resName, "");
// The typed resource's data is always a String, so need to inferFromValue the value.
if (typedRes == null) {
throw new Resources.NotFoundException(resName.getFullyQualifiedName());
}
switch (typedRes.getResType()) {
case BOOLEAN: case COLOR: case INTEGER: case FLOAT:
valueMap.put(entry.getKey(), parseValue(typedRes.getData().toString()));
break;
default:
valueMap.put(entry.getKey(),typedRes.getData());
}
break;
}
} else if (entry.getValue() == VALUE_TYPE.VALUE) {
// Raw value, so inferFromValue it in to the appropriate type and store it
valueMap.put(entry.getKey(), parseValue(value));
}
}
// Finished parsing, mark as initialised
initialised = true;
}
}
public Map<String, Object> getValueMap() {
return valueMap;
}
private enum VALUE_TYPE {
RESOURCE,
VALUE
}
private Object parseValue(String value) {
if (value == null) {
return null;
} else if ("true".equals(value)) {
return true;
} else if ("false".equals(value)) {
return false;
} else if (value.startsWith("#")) {
// if it's a color, add it and continue
try {
return ResourceHelper.getColor(value);
} catch (NumberFormatException e) {
/* Not a color */
}
} else if (value.contains(".")) {
// most likely a float
try {
return Float.parseFloat(value);
} catch (NumberFormatException e) {
// Not a float
}
} else {
// if it's an int, add it and continue
try {
return Integer.parseInt(value);
} catch (NumberFormatException ei) {
// Not an int
}
}
// Not one of the above types, keep as String
return value;
}
}