15117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richardpackage com.xtremelabs.robolectric.res; 25117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard 3284a307f028fc1b9c6175a28b60280bc53b5dbe6adriancowhamimport android.R; 4aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wuimport android.graphics.drawable.AnimationDrawable; 5fac8bbf7dfc7904540716be8649b2f5a5c9f6d15adriancowhamimport android.graphics.drawable.Drawable; 6fac8bbf7dfc7904540716be8649b2f5a5c9f6d15adriancowhamimport android.graphics.drawable.LayerDrawable; 7fac8bbf7dfc7904540716be8649b2f5a5c9f6d15adriancowhamimport android.graphics.drawable.StateListDrawable; 8284a307f028fc1b9c6175a28b60280bc53b5dbe6adriancowhamimport com.xtremelabs.robolectric.Robolectric; 9284a307f028fc1b9c6175a28b60280bc53b5dbe6adriancowhamimport com.xtremelabs.robolectric.shadows.ShadowStateListDrawable; 10aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wuimport org.w3c.dom.Document; 11aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wuimport org.w3c.dom.NamedNodeMap; 12aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wuimport org.w3c.dom.Node; 13aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wuimport org.w3c.dom.NodeList; 14aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu 15aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wuimport java.io.File; 16aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wuimport java.io.IOException; 17aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wuimport java.util.HashMap; 18aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wuimport java.util.Map; 19284a307f028fc1b9c6175a28b60280bc53b5dbe6adriancowham 205117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard/** 215117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard * DrawableResourceLoader 225117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard */ 235117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richardpublic class DrawableResourceLoader extends XmlLoader { 24aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu 25aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu // Put all the states for a StateListDrawable in the into a Map for looking up 26aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu // http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList 27aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu private static final Map<String, Integer> stateMap = new HashMap<String, Integer>(); 28aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu static { 29aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu stateMap.put("android:state_selected", R.attr.state_selected); 30aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu stateMap.put("android:state_pressed", R.attr.state_pressed); 31aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu stateMap.put("android:state_focused", R.attr.state_focused); 32aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu stateMap.put("android:state_checkable", R.attr.state_checkable); 33aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu stateMap.put("android:state_checked", R.attr.state_checked); 34aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu stateMap.put("android:state_enabled", R.attr.state_enabled); 35aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu stateMap.put("android:state_window_focused", R.attr.state_window_focused); 36aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu } 37aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu 385117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard /** document */ 395117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard protected Map<String, Document> documents = new HashMap<String, Document>(); 405117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard 415117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard /** resource directory */ 425117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard protected File resourceDirectory; 435117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard 445117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard /** 455117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard * DrawableResourceLoader constructor. 46aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu * 47aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu * @param extractor Extractor 48aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu * @param resourceDirectory Resource directory 495117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard */ 50f2906888dbe454d6b607e123cc5fdfebd190372bJesse Toth & Tim Labeeuw public DrawableResourceLoader(ResourceExtractor extractor, File resourceDirectory) { 515117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard super(extractor); 525117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard this.resourceDirectory = resourceDirectory; 535117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard } 545117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard 555117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard /** 565117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard * Check if resource is xml. 57aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu * 58aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu * @param resourceId Resource id 595117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard * @return Boolean 605117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard */ 615117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard public boolean isXml(int resourceId) { 62f2906888dbe454d6b607e123cc5fdfebd190372bJesse Toth & Tim Labeeuw return documents.containsKey(resourceExtractor.getResourceName(resourceId)); 635117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard } 645117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard 65aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu public Drawable getXmlDrawable(int resId) { 66aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu 67aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu if (!isXml(resId)) { 68aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu return null; 69aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu } 70fac8bbf7dfc7904540716be8649b2f5a5c9f6d15adriancowham 71aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu Document xmlDoc = documents.get(resourceExtractor.getResourceName(resId)); 72aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu NodeList nodes = xmlDoc.getElementsByTagName("selector"); 73aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu if (nodes != null && nodes.getLength() > 0) { 74aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu return buildStateListDrawable(xmlDoc); 75aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu } 76fac8bbf7dfc7904540716be8649b2f5a5c9f6d15adriancowham 77aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu nodes = xmlDoc.getElementsByTagName("layer-list"); 78aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu if (nodes != null && nodes.getLength() > 0) { 79aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu return new LayerDrawable(null); 80aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu } 81fac8bbf7dfc7904540716be8649b2f5a5c9f6d15adriancowham 82aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu nodes = xmlDoc.getElementsByTagName("animation-list"); 83aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu if (nodes != null && nodes.getLength() > 0) { 84aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu return new AnimationDrawable(); 85aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu } 86aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu 87aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu return null; 88fac8bbf7dfc7904540716be8649b2f5a5c9f6d15adriancowham } 89aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu 905117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard /** 915117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard * Store document locally keyed by resource name. 92aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu * 93aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu * @param xmlFile Xml file 94aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu * @param document Document 95aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu * @param isSystem System resource 965117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard * @throws Exception 975117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard * @see com.xtremelabs.robolectric.res.XmlLoader#processResourceXml(java.io.File, 985117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard * org.w3c.dom.Document, boolean) 995117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard */ 1005117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard @Override 101f2906888dbe454d6b607e123cc5fdfebd190372bJesse Toth & Tim Labeeuw protected void processResourceXml(File xmlFile, Document document, boolean isSystem) throws Exception { 1025117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard String name = toResourceName(xmlFile); 1035117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard if (!documents.containsKey(name)) { 104f2906888dbe454d6b607e123cc5fdfebd190372bJesse Toth & Tim Labeeuw if (isSystem) { 105f2906888dbe454d6b607e123cc5fdfebd190372bJesse Toth & Tim Labeeuw name = "android:" + name; 106f2906888dbe454d6b607e123cc5fdfebd190372bJesse Toth & Tim Labeeuw } 1075117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard documents.put(name, document); 1085117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard } 1095117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard } 1105117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard 1115117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard /** 1125117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard * Convert file name to resource name. 113aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu * 114aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu * @param xmlFile Xml File 1155117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard * @return Resource name 1165117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard */ 1175117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard private String toResourceName(File xmlFile) { 1185117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard try { 1195117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard return xmlFile.getCanonicalPath().replaceAll("[/\\\\\\\\]", "/") 1205117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard .replaceAll("^.*?/res/", "").replaceAll("\\..+$", ""); 1215117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard } catch (IOException e) { 1225117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard throw new RuntimeException(e); 1235117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard } 1245117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard } 1255117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard 126aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu 1275117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard /** 1285117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard * Get drawables by resource id. 129aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu * 130aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu * @param resourceId Resource id 1315117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard * @return Drawables 1325117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard */ 1335117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard protected int[] getDrawableIds(int resourceId) { 134f2906888dbe454d6b607e123cc5fdfebd190372bJesse Toth & Tim Labeeuw String resourceName = resourceExtractor.getResourceName(resourceId); 135f2906888dbe454d6b607e123cc5fdfebd190372bJesse Toth & Tim Labeeuw Document document = documents.get(resourceName); 1365117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard 1375117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard NodeList items = document.getElementsByTagName("item"); 1385117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard int[] drawableIds = new int[items.getLength()]; 1395117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard 1405117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard for (int i = 0; i < items.getLength(); i++) { 141f2906888dbe454d6b607e123cc5fdfebd190372bJesse Toth & Tim Labeeuw if (resourceName.startsWith("android:")) { 142f2906888dbe454d6b607e123cc5fdfebd190372bJesse Toth & Tim Labeeuw drawableIds[i] = -1; 143f2906888dbe454d6b607e123cc5fdfebd190372bJesse Toth & Tim Labeeuw } else { 144a6d34e0b33533736dd8425a582ed48b40f18ac06Michael Portuesi Node item = items.item(i); 145a6d34e0b33533736dd8425a582ed48b40f18ac06Michael Portuesi Node drawableName = item.getAttributes().getNamedItem("android:drawable"); 146a6d34e0b33533736dd8425a582ed48b40f18ac06Michael Portuesi if (drawableName != null) { 147a6d34e0b33533736dd8425a582ed48b40f18ac06Michael Portuesi drawableIds[i] = resourceExtractor.getResourceId(drawableName.getNodeValue()); 148a6d34e0b33533736dd8425a582ed48b40f18ac06Michael Portuesi } 149f2906888dbe454d6b607e123cc5fdfebd190372bJesse Toth & Tim Labeeuw } 1505117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard } 1515117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard 1525117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard return drawableIds; 1535117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard } 154aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu 155aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu public boolean isAnimationDrawable(int resourceId) { 156aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu Document document = documents.get(resourceExtractor.getResourceName(resourceId)); 157aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu return "animation-list".equals(document.getDocumentElement().getLocalName()); 158aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu } 159aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu 160aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu private StateListDrawable buildStateListDrawable(Document d) { 161aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu StateListDrawable drawable = new StateListDrawable(); 162aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu ShadowStateListDrawable shDrawable = Robolectric.shadowOf(drawable); 163aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu NodeList items = d.getElementsByTagName("item"); 164aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu for (int i = 0; i < items.getLength(); i++) { 165aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu Node node = items.item(i); 166aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu Node drawableName = node.getAttributes().getNamedItem("android:drawable"); 167aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu if (drawableName != null) { 168aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu int resId = resourceExtractor.getResourceId(drawableName.getNodeValue()); 169aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu int stateId = getStateId(node); 170aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu shDrawable.addState(stateId, resId); 171aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu } 172aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu } 173aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu return drawable; 174aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu } 175aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu 176aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu private int getStateId(Node node) { 177aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu NamedNodeMap attrs = node.getAttributes(); 178aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu for (String state : stateMap.keySet()) { 179aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu Node attr = attrs.getNamedItem(state); 180aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu if (attr != null) { 181aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu return stateMap.get(state); 182aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu } 183aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu } 184aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu 185aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu // if a state wasn't specified, return the default state 186aec1d0888fe04efd0cde7514e155870b18c41286Rick Kawala & Wei Wu return R.attr.state_active; 187284a307f028fc1b9c6175a28b60280bc53b5dbe6adriancowham } 1885117035453920f3d4d0f3969bdab0305dcdb94baJoe Moore & Ryan Richard} 189