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.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 name = matcher.group(NAME).trim(); 38 39 hashCode = computeHashCode(); 40 if (packageName.equals("xmlns")) throw new IllegalStateException("\"" + fullyQualifiedName + "\" unexpected"); 41 } 42 43 /** 44 * @return null if the resource could not be qualified. 45 */ qualifyResourceName(@onnull String possiblyQualifiedResourceName, String defaultPackageName, String defaultType)46 public static String qualifyResourceName(@Nonnull String possiblyQualifiedResourceName, String defaultPackageName, String defaultType) { 47 ResName resName = qualifyResName(possiblyQualifiedResourceName, defaultPackageName, defaultType); 48 return resName != null ? resName.getFullyQualifiedName() : null; 49 } 50 qualifyResName(@onnull String possiblyQualifiedResourceName, ResName defaults)51 public static ResName qualifyResName(@Nonnull String possiblyQualifiedResourceName, ResName defaults) { 52 return qualifyResName(possiblyQualifiedResourceName, defaults.packageName, defaults.type); 53 } 54 qualifyResName(@onnull String possiblyQualifiedResourceName, String defaultPackageName, String defaultType)55 public static ResName qualifyResName(@Nonnull String possiblyQualifiedResourceName, String defaultPackageName, String defaultType) { 56 int indexOfColon = possiblyQualifiedResourceName.indexOf(':'); 57 int indexOfSlash = possiblyQualifiedResourceName.indexOf('/'); 58 String type = null; 59 String packageName = null; 60 String name = possiblyQualifiedResourceName; 61 if (indexOfColon > indexOfSlash) { 62 if (indexOfSlash > 0) { 63 type = possiblyQualifiedResourceName.substring(0, indexOfSlash); 64 } 65 packageName = possiblyQualifiedResourceName.substring(indexOfSlash + 1, indexOfColon); 66 name = possiblyQualifiedResourceName.substring(indexOfColon + 1); 67 } else if (indexOfSlash > indexOfColon) { 68 if (indexOfColon > 0) { 69 packageName = possiblyQualifiedResourceName.substring(0, indexOfColon); 70 } 71 type = possiblyQualifiedResourceName.substring(indexOfColon + 1, indexOfSlash); 72 name = possiblyQualifiedResourceName.substring(indexOfSlash + 1); 73 } 74 75 if ((type == null && defaultType == null) || (packageName == null && defaultPackageName == null)) { 76 return null; 77 } 78 79 if (packageName == null) { 80 packageName = defaultPackageName; 81 } else if ("*android".equals(packageName)) { 82 packageName = "android"; 83 } 84 85 return new ResName( 86 packageName, 87 type == null ? defaultType : type, 88 name); 89 } 90 qualifyResName(String possiblyQualifiedResourceName, String contextPackageName)91 public static String qualifyResName(String possiblyQualifiedResourceName, String contextPackageName) { 92 if (possiblyQualifiedResourceName == null) { 93 return null; 94 } 95 96 if (AttributeResource.isNull(possiblyQualifiedResourceName)) { 97 return null; 98 } 99 100 // Was not able to fully qualify the resource name 101 String fullyQualifiedResourceName = qualifyResourceName(possiblyQualifiedResourceName, contextPackageName, null); 102 if (fullyQualifiedResourceName == null) { 103 return null; 104 } 105 106 return fullyQualifiedResourceName.replaceAll("[@+]", ""); 107 } 108 qualifyFromFilePath(@onnull final String packageName, @Nonnull final String filePath)109 public static ResName qualifyFromFilePath(@Nonnull final String packageName, @Nonnull final String filePath) { 110 final FileFsFile filePathFile = new FileFsFile(new File(filePath)); 111 final String type = filePathFile.getParent().getName().split("-", 0)[0]; 112 final String name = filePathFile.getBaseName(); 113 114 return new ResName(packageName, type, name); 115 } 116 117 @Override equals(Object o)118 public boolean equals(Object o) { 119 if (this == o) return true; 120 if (o == null || getClass() != o.getClass()) return false; 121 122 ResName resName = (ResName) o; 123 124 if (hashCode() != resName.hashCode()) return false; 125 126 if (!packageName.equals(resName.packageName)) return false; 127 if (!type.equals(resName.type)) return false; 128 if (!name.equals(resName.name)) return false; 129 130 return true; 131 } 132 133 @Override hashCode()134 public int hashCode() { 135 return hashCode; 136 } 137 138 @Override toString()139 public String toString() { 140 return "ResName{" + getFullyQualifiedName() + "}"; 141 } 142 getFullyQualifiedName()143 public String getFullyQualifiedName() { 144 return packageName + ":" + type + "/" + name; 145 } 146 getNamespaceUri()147 public String getNamespaceUri() { 148 return "http://schemas.android.com/apk/res/" + packageName; 149 } 150 withPackageName(String packageName)151 public ResName withPackageName(String packageName) { 152 if (packageName.equals(this.packageName)) return this; 153 return new ResName(packageName, type, name); 154 } 155 mustBe(String expectedType)156 public void mustBe(String expectedType) { 157 if (!type.equals(expectedType)) { 158 throw new RuntimeException("expected " + getFullyQualifiedName() + " to be a " + expectedType + ", is a " + type); 159 } 160 } 161 computeHashCode()162 private int computeHashCode() { 163 int result = packageName.hashCode(); 164 result = 31 * result + type.hashCode(); 165 result = 31 * result + name.hashCode(); 166 return result; 167 } 168 } 169