blob: 1d80ae490d6a58101cf2a35a8d49d84d3932620c [file] [log] [blame]
package com.xtremelabs.robolectric.res;
import java.io.File;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.xtremelabs.robolectric.Robolectric;
import com.xtremelabs.robolectric.tester.android.util.TestAttributeSet;
import com.xtremelabs.robolectric.util.I18nException;
import android.content.Context;
import android.preference.Preference;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.util.AttributeSet;
public class PreferenceLoader extends XmlLoader {
private Map<String, PreferenceNode> prefNodesByResourceName = new HashMap<String, PreferenceNode>();
public PreferenceLoader(ResourceExtractor resourceExtractor) {
super(resourceExtractor);
}
@Override
protected void processResourceXml(File xmlFile, Document document, boolean isSystem) throws Exception {
PreferenceNode topLevelNode = new PreferenceNode("top-level", new HashMap<String, String>());
processChildren(document.getChildNodes(), topLevelNode);
prefNodesByResourceName.put( "xml/" + xmlFile.getName().replace(".xml", ""), topLevelNode.getChildren().get(0));
}
private void processChildren(NodeList childNodes, PreferenceNode parent) {
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
processNode(node, parent);
}
}
private void processNode(Node node, PreferenceNode parent) {
String name = node.getNodeName();
NamedNodeMap attributes = node.getAttributes();
Map<String, String> attrMap = new HashMap<String, String>();
if (attributes != null) {
int length = attributes.getLength();
for (int i = 0; i < length; i++) {
Node attr = attributes.item(i);
attrMap.put(attr.getNodeName(), attr.getNodeValue());
}
}
if (!name.startsWith("#")) {
PreferenceNode prefNode = new PreferenceNode(name, attrMap);
if (parent != null) parent.addChild(prefNode);
processChildren(node.getChildNodes(), prefNode);
}
}
public PreferenceScreen inflatePreferences(Context context, int resourceId) {
return inflatePreferences(context, resourceExtractor.getResourceName(resourceId));
}
public PreferenceScreen inflatePreferences(Context context, String key) {
try {
PreferenceNode prefNode = prefNodesByResourceName.get(key);
return (PreferenceScreen) prefNode.inflate(context, null);
} catch (I18nException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("error inflating " + key, e);
}
}
public class PreferenceNode {
private String name;
private final Map<String, String> attributes;
private List<PreferenceNode> children = new ArrayList<PreferenceNode>();
public PreferenceNode(String name, Map<String, String> attributes) {
this.name = name;
this.attributes = attributes;
}
public List<PreferenceNode> getChildren() {
return children;
}
public void addChild(PreferenceNode prefNode) {
children.add(prefNode);
}
public Preference inflate(Context context, Preference parent) throws Exception {
Preference preference = create(context, (PreferenceGroup) parent);
for (PreferenceNode child : children) {
child.inflate(context, preference);
}
return preference;
}
private Preference create(Context context, PreferenceGroup parent) throws Exception {
Preference preference = constructPreference(context, parent);
if (parent != null && parent != preference) {
parent.addPreference(preference);
}
return preference;
}
private Preference constructPreference(Context context, PreferenceGroup parent) throws Exception {
Class<? extends Preference> clazz = pickViewClass();
if (clazz.equals(PreferenceScreen.class)) {
return Robolectric.newInstanceOf(PreferenceScreen.class);
}
try {
TestAttributeSet attributeSet = new TestAttributeSet(attributes);
if (strictI18n) {
attributeSet.validateStrictI18n();
}
return ((Constructor<? extends Preference>) clazz.getConstructor(Context.class, AttributeSet.class)).newInstance(context, attributeSet);
} catch (NoSuchMethodException e) {
try {
return ((Constructor<? extends Preference>) clazz.getConstructor(Context.class)).newInstance(context);
} catch (NoSuchMethodException e1) {
return ((Constructor<? extends Preference>) clazz.getConstructor(Context.class, String.class)).newInstance(context, "");
}
}
}
private Class<? extends Preference> pickViewClass() {
Class<? extends Preference> clazz = loadClass(name);
if (clazz == null) {
clazz = loadClass("android.preference." + name);
}
if (clazz == null) {
throw new RuntimeException("couldn't find preference class " + name);
}
return clazz;
}
private Class<? extends Preference> loadClass(String className) {
try {
//noinspection unchecked
return (Class<? extends Preference>) getClass().getClassLoader().loadClass(className);
} catch (ClassNotFoundException e) {
return null;
}
}
}
}