1 package org.robolectric.res; 2 3 import java.io.File; 4 import java.util.regex.Matcher; 5 import java.util.regex.Pattern; 6 import javax.annotation.Nonnull; 7 8 public class ResName { 9 public static final String ID_TYPE = "id"; 10 11 private static final Pattern FQN_PATTERN = Pattern.compile("^([^:]*):([^/]+)/(.+)$"); 12 private static final int NAMESPACE = 1; 13 private static final int TYPE = 2; 14 private static final int NAME = 3; 15 16 public final @Nonnull String packageName; 17 public final @Nonnull String type; 18 public final @Nonnull String name; 19 20 public final int hashCode; 21 ResName(@onnull String packageName, @Nonnull String type, @Nonnull String name)22 public ResName(@Nonnull String packageName, @Nonnull String type, @Nonnull String name) { 23 this.packageName = packageName; 24 this.type = type.trim(); 25 this.name = name.indexOf('.') != -1 ? name.replace('.', '_').trim() : name.trim(); 26 27 hashCode = computeHashCode(); 28 } 29 ResName(@onnull String fullyQualifiedName)30 public ResName(@Nonnull String fullyQualifiedName) { 31 Matcher matcher = FQN_PATTERN.matcher(fullyQualifiedName.trim()); 32 if (!matcher.find()) { 33 throw new IllegalStateException("\"" + fullyQualifiedName + "\" is not fully qualified"); 34 } 35 packageName = matcher.group(NAMESPACE); 36 type = matcher.group(TYPE).trim(); 37 String nameStr = matcher.group(NAME); 38 name = nameStr.indexOf('.') != -1 ? nameStr.replace('.', '_') : nameStr; 39 40 hashCode = computeHashCode(); 41 if (packageName.equals("xmlns")) throw new IllegalStateException("\"" + fullyQualifiedName + "\" unexpected"); 42 } 43 44 /** 45 * @return null if the resource could not be qualified. 46 */ qualifyResourceName(@onnull String possiblyQualifiedResourceName, String defaultPackageName, String defaultType)47 public static String qualifyResourceName(@Nonnull String possiblyQualifiedResourceName, String defaultPackageName, String defaultType) { 48 ResName resName = qualifyResName(possiblyQualifiedResourceName, defaultPackageName, defaultType); 49 return resName != null ? resName.getFullyQualifiedName() : null; 50 } 51 qualifyResName(@onnull String possiblyQualifiedResourceName, ResName defaults)52 public static ResName qualifyResName(@Nonnull String possiblyQualifiedResourceName, ResName defaults) { 53 return qualifyResName(possiblyQualifiedResourceName, defaults.packageName, defaults.type); 54 } 55 qualifyResName(@onnull String possiblyQualifiedResourceName, String defaultPackageName, String defaultType)56 public static ResName qualifyResName(@Nonnull String possiblyQualifiedResourceName, String defaultPackageName, String defaultType) { 57 int indexOfColon = possiblyQualifiedResourceName.indexOf(':'); 58 int indexOfSlash = possiblyQualifiedResourceName.indexOf('/'); 59 String type = null; 60 String packageName = null; 61 String name = possiblyQualifiedResourceName; 62 if (indexOfColon > indexOfSlash) { 63 if (indexOfSlash > 0) { 64 type = possiblyQualifiedResourceName.substring(0, indexOfSlash); 65 } 66 packageName = possiblyQualifiedResourceName.substring(indexOfSlash + 1, indexOfColon); 67 name = possiblyQualifiedResourceName.substring(indexOfColon + 1); 68 } else if (indexOfSlash > indexOfColon) { 69 if (indexOfColon > 0) { 70 packageName = possiblyQualifiedResourceName.substring(0, indexOfColon); 71 } 72 type = possiblyQualifiedResourceName.substring(indexOfColon + 1, indexOfSlash); 73 name = possiblyQualifiedResourceName.substring(indexOfSlash + 1); 74 } 75 76 if ((type == null && defaultType == null) || (packageName == null && defaultPackageName == null)) { 77 return null; 78 } 79 80 return new ResName(packageName == null ? defaultPackageName : packageName, 81 type == null ? defaultType : type, 82 name); 83 } 84 qualifyResName(String possiblyQualifiedResourceName, String contextPackageName)85 public static String qualifyResName(String possiblyQualifiedResourceName, String contextPackageName) { 86 if (possiblyQualifiedResourceName == null) { 87 return null; 88 } 89 90 if (AttributeResource.isNull(possiblyQualifiedResourceName)) { 91 return null; 92 } 93 94 // Was not able to fully qualify the resource name 95 String fullyQualifiedResourceName = qualifyResourceName(possiblyQualifiedResourceName, contextPackageName, null); 96 if (fullyQualifiedResourceName == null) { 97 return null; 98 } 99 100 return fullyQualifiedResourceName.replaceAll("[@+]", ""); 101 } 102 qualifyFromFilePath(@onnull final String packageName, @Nonnull final String filePath)103 public static ResName qualifyFromFilePath(@Nonnull final String packageName, @Nonnull final String filePath) { 104 final FileFsFile filePathFile = new FileFsFile(new File(filePath)); 105 final String type = filePathFile.getParent().getName().split("-")[0]; 106 final String name = filePathFile.getBaseName(); 107 108 return new ResName(packageName, type, name); 109 } 110 111 @Override equals(Object o)112 public boolean equals(Object o) { 113 if (this == o) return true; 114 if (o == null || getClass() != o.getClass()) return false; 115 116 ResName resName = (ResName) o; 117 118 if (hashCode() != resName.hashCode()) return false; 119 120 if (!packageName.equals(resName.packageName)) return false; 121 if (!type.equals(resName.type)) return false; 122 if (!name.equals(resName.name)) return false; 123 124 return true; 125 } 126 127 @Override hashCode()128 public int hashCode() { 129 return hashCode; 130 } 131 132 @Override toString()133 public String toString() { 134 return "ResName{" + getFullyQualifiedName() + "}"; 135 } 136 getFullyQualifiedName()137 public String getFullyQualifiedName() { 138 return packageName + ":" + type + "/" + name; 139 } 140 getNamespaceUri()141 public String getNamespaceUri() { 142 return "http://schemas.android.com/apk/res/" + packageName; 143 } 144 withPackageName(String packageName)145 public ResName withPackageName(String packageName) { 146 if (packageName.equals(this.packageName)) return this; 147 return new ResName(packageName, type, name); 148 } 149 mustBe(String expectedType)150 public void mustBe(String expectedType) { 151 if (!type.equals(expectedType)) { 152 throw new RuntimeException("expected " + getFullyQualifiedName() + " to be a " + expectedType + ", is a " + type); 153 } 154 } 155 computeHashCode()156 private int computeHashCode() { 157 int result = packageName.hashCode(); 158 result = 31 * result + type.hashCode(); 159 result = 31 * result + name.hashCode(); 160 return result; 161 } 162 } 163