1826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parkerpackage com.xtremelabs.robolectric.res; 2826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 3d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultzimport java.io.File; 4d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultzimport java.util.ArrayList; 5d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultzimport java.util.HashMap; 6d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultzimport java.util.List; 7d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultzimport java.util.Map; 8bb2f85d397fa65f20c6932186d9156ced9beb184Michael Portuesi 9826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parkerimport org.w3c.dom.Document; 10826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parkerimport org.w3c.dom.NamedNodeMap; 11826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parkerimport org.w3c.dom.Node; 12826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parkerimport org.w3c.dom.NodeList; 13826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 14d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultzimport android.content.Context; 15d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultzimport android.text.TextUtils; 16d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultzimport android.view.Menu; 17d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultzimport android.view.MenuItem; 18d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultzimport android.view.SubMenu; 19d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz 20d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultzimport com.xtremelabs.robolectric.tester.android.util.TestAttributeSet; 21d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultzimport com.xtremelabs.robolectric.util.I18nException; 22826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 23826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parkerpublic class MenuLoader extends XmlLoader { 24826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker private Map<String, MenuNode> menuNodesByMenuName = new HashMap<String, MenuNode>(); 25ba7a1270d36fb28e5f90be135431700c4ce81504Phil Goodwin private AttrResourceLoader attrResourceLoader; 26826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 27ba7a1270d36fb28e5f90be135431700c4ce81504Phil Goodwin public MenuLoader(ResourceExtractor resourceExtractor, AttrResourceLoader attrResourceLoader) { 28826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker super(resourceExtractor); 29ba7a1270d36fb28e5f90be135431700c4ce81504Phil Goodwin this.attrResourceLoader = attrResourceLoader; 30826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 31826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 32826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker @Override 3329610b43047065c5dc66452d33f0113ac7e65fe8Phil Goodwin protected void processResourceXml(File xmlFile, Document document, boolean ignored) throws Exception { 34bb2f85d397fa65f20c6932186d9156ced9beb184Michael Portuesi MenuNode topLevelNode = new MenuNode("top-level", new HashMap<String, String>()); 3540c6251719cccc0a84ae99c976d2836b14374ce6Christian Williams 3640c6251719cccc0a84ae99c976d2836b14374ce6Christian Williams NodeList items = document.getChildNodes(); 3740c6251719cccc0a84ae99c976d2836b14374ce6Christian Williams if (items.getLength() != 1) 3840c6251719cccc0a84ae99c976d2836b14374ce6Christian Williams throw new RuntimeException("Expected only one top-level item in menu file " + xmlFile.getName()); 3940c6251719cccc0a84ae99c976d2836b14374ce6Christian Williams if (items.item(0).getNodeName().compareTo("menu") != 0) 4040c6251719cccc0a84ae99c976d2836b14374ce6Christian Williams throw new RuntimeException("Expected a top-level item called 'menu' in menu file " + xmlFile.getName()); 41041a15421126d0667517def59cef9b284359d729Tom Parker 42041a15421126d0667517def59cef9b284359d729Tom Parker processChildren(items.item(0).getChildNodes(), topLevelNode); 43d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz menuNodesByMenuName.put("menu/" + xmlFile.getName().replace(".xml", ""), topLevelNode); 44826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 45826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 46826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker private void processChildren(NodeList childNodes, MenuNode parent) { 47826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker for (int i = 0; i < childNodes.getLength(); i++) { 48826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker Node node = childNodes.item(i); 49826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker processNode(node, parent); 50826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 51826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 52826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 53826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker private void processNode(Node node, MenuNode parent) { 54826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker String name = node.getNodeName(); 55826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker NamedNodeMap attributes = node.getAttributes(); 56826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker Map<String, String> attrMap = new HashMap<String, String>(); 57826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker if (attributes != null) { 58826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker int length = attributes.getLength(); 59826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker for (int i = 0; i < length; i++) { 60826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker Node attr = attributes.item(i); 61826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker attrMap.put(attr.getNodeName(), attr.getNodeValue()); 62826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 63826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 64826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 65826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker if (!name.startsWith("#")) { 66bb2f85d397fa65f20c6932186d9156ced9beb184Michael Portuesi MenuNode menuNode = new MenuNode(name, attrMap); 6740c6251719cccc0a84ae99c976d2836b14374ce6Christian Williams parent.addChild(menuNode); 68d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz NodeList children = node.getChildNodes(); 69d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz if (children != null && children.getLength() != 0) { 70d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz for (int i = 0; i < children.getLength(); i++) { 71d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz Node nodei = children.item(i); 72d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz if (childToIgnore(nodei)) { 73d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz continue; 74d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz } else if (validChildren(nodei)) { 75d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz // recursively add all nodes 76d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz processNode(nodei, menuNode); 77d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz } else { 78d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz throw new RuntimeException("Unknown menu node" 79d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz + nodei.getNodeName()); 80d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz } 81d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz } 82d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz } 8340c6251719cccc0a84ae99c976d2836b14374ce6Christian Williams } 84826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 85826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 86d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz private static boolean childToIgnore(Node nodei) { 87d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz return TextUtils.isEmpty(nodei.getNodeName()) 88d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz || nodei.getNodeName().startsWith("#"); 89d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz } 90d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz 91d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz private static boolean validChildren(Node nodei) { 92d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz return nodei.getNodeName().equals("item") 93d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz || nodei.getNodeName().equals("menu") 94d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz || nodei.getNodeName().equals("group"); 95d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz } 96d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz 97041a15421126d0667517def59cef9b284359d729Tom Parker public void inflateMenu(Context context, String key, Menu root) { 98041a15421126d0667517def59cef9b284359d729Tom Parker inflateMenu(context, key, null, root); 99826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 100826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 101041a15421126d0667517def59cef9b284359d729Tom Parker public void inflateMenu(Context context, int resourceId, Menu root) { 102d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz inflateMenu(context, resourceExtractor.getResourceName(resourceId), 103d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz root); 104826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 105826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 106d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz private void inflateMenu(Context context, String key, 107d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz Map<String, String> attributes, Menu root) { 108826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker MenuNode menuNode = menuNodesByMenuName.get(key); 109826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker if (menuNode == null) { 110826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker throw new RuntimeException("Could not find menu " + key); 111826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 112826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker try { 113826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker if (attributes != null) { 114826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker for (Map.Entry<String, String> entry : attributes.entrySet()) { 115826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker if (!entry.getKey().equals("menu")) { 116d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz menuNode.attributes.put(entry.getKey(), 117d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz entry.getValue()); 118826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 119826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 120826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 121041a15421126d0667517def59cef9b284359d729Tom Parker menuNode.inflate(context, root); 122bb2f85d397fa65f20c6932186d9156ced9beb184Michael Portuesi } catch (I18nException e) { 123bb2f85d397fa65f20c6932186d9156ced9beb184Michael Portuesi throw e; 124826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } catch (Exception e) { 125826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker throw new RuntimeException("error inflating " + key, e); 126826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 127826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 128826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 129826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker public class MenuNode { 130826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker private String name; 131ba7a1270d36fb28e5f90be135431700c4ce81504Phil Goodwin private final TestAttributeSet attributes; 132826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 133826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker private List<MenuNode> children = new ArrayList<MenuNode>(); 134826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 135bb2f85d397fa65f20c6932186d9156ced9beb184Michael Portuesi public MenuNode(String name, Map<String, String> attributes) { 136826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker this.name = name; 137d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz this.attributes = new TestAttributeSet(attributes, 138d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz resourceExtractor, attrResourceLoader, null, false); 139826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 140826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 141826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker public List<MenuNode> getChildren() { 142826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker return children; 143826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 144826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 145826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker public void addChild(MenuNode MenuNode) { 146826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker children.add(MenuNode); 147826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 148826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker 149d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz private boolean isSubMenuItem(MenuNode child) { 150d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz List<MenuLoader.MenuNode> ch = child.children; 151d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz return ch != null && ch.size() == 1 && "menu".equals(ch.get(0).name); 152d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz } 153d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz 154d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz private void addChildrenInGroup(MenuNode source, int groupId, Menu root) { 155d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz for (MenuNode child : source.children) { 156d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz String name = child.name; 157d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz TestAttributeSet attributes = child.attributes; 158d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz if (strictI18n) { 159d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz attributes.validateStrictI18n(); 160d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz } 161d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz if (name.equals("item")) { 162d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz if (isSubMenuItem(child)) { 163d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz SubMenu sub = root.addSubMenu(groupId, attributes 164d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz .getAttributeResourceValue("android", "id", 0), 165d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz 0, attributes.getAttributeValue("android", "title")); 166d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz MenuNode subMenuNode = child.children.get(0); 167d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz addChildrenInGroup(subMenuNode, groupId, sub); 168d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz } else { 169d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz MenuItem menuItem = root.add(groupId, attributes 170d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz .getAttributeResourceValue("android", "id", 0), 171d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz 0, attributes.getAttributeValue("android", "title")); 172d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz } 173d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz } else if (name.equals("group")) { 174d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz int newGroupId = attributes.getAttributeResourceValue("android", "id", 0); 175d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz addChildrenInGroup(child, newGroupId, root); 176bb2f85d397fa65f20c6932186d9156ced9beb184Michael Portuesi } 177826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 178826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker } 179d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz 180d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz public void inflate(Context context, Menu root) throws Exception { 181d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz addChildrenInGroup(this, 0, root); 182d6cd04adb85895b340ce9b6df33b749b22099c43Joe Moore and Tyler Schultz } 18340c6251719cccc0a84ae99c976d2836b14374ce6Christian Williams } 184826bfc77015bfd1044cfb0f98b0fafe65f1e465eTom Parker} 185