1 package org.robolectric.res; 2 3 import java.nio.file.Path; 4 import java.util.regex.Matcher; 5 import java.util.regex.Pattern; 6 import org.robolectric.res.android.ConfigDescription; 7 import org.robolectric.res.android.ResTable_config; 8 9 /** 10 * Android qualifers as defined by 11 * https://developer.android.com/guide/topics/resources/providing-resources.html 12 */ 13 @SuppressWarnings("NewApi") 14 public class Qualifiers { 15 private static final Pattern DIR_QUALIFIER_PATTERN = Pattern.compile("^[^-]+(?:-([^/]*))?/?$"); 16 17 // Matches a version qualifier like "v14". Parentheses capture the numeric 18 // part for easy retrieval with Matcher.group(2). 19 private static final Pattern SCREEN_WIDTH_PATTERN = Pattern.compile("^w([0-9]+)dp"); 20 private static final Pattern SMALLEST_SCREEN_WIDTH_PATTERN = Pattern.compile("^sw([0-9]+)dp"); 21 private static final Pattern VERSION_QUALIFIER_PATTERN = Pattern.compile("(v)([0-9]+)$"); 22 private static final Pattern ORIENTATION_QUALIFIER_PATTERN = Pattern.compile("(land|port)"); 23 24 private final String qualifiers; 25 private final ResTable_config config; 26 parse(String qualifiers)27 public static Qualifiers parse(String qualifiers) { 28 return parse(qualifiers, true); 29 } 30 parse(String qualifiers, boolean applyVersionForCompat)31 public static Qualifiers parse(String qualifiers, boolean applyVersionForCompat) { 32 final ResTable_config config = new ResTable_config(); 33 if (!qualifiers.isEmpty() 34 && !ConfigDescription.parse(qualifiers, config, applyVersionForCompat)) { 35 throw new IllegalArgumentException( 36 "failed to parse qualifiers '" 37 + qualifiers 38 + "'. See" 39 + " https://developer.android.com/guide/topics/resources/providing-resources.html#QualifierRules" 40 + " for expected format."); 41 } 42 43 return new Qualifiers(qualifiers, config); 44 } 45 Qualifiers(String qualifiers, ResTable_config config)46 protected Qualifiers(String qualifiers, ResTable_config config) { 47 this.qualifiers = qualifiers; 48 this.config = config; 49 } 50 getConfig()51 public ResTable_config getConfig() { 52 return config; 53 } 54 55 @Override toString()56 public String toString() { 57 return qualifiers; 58 } 59 fromParentDir(Path parentDir)60 public static Qualifiers fromParentDir(Path parentDir) { 61 if (parentDir == null) { 62 return parse(""); 63 } else { 64 String parentDirName = parentDir.getFileName().toString(); 65 Matcher matcher = DIR_QUALIFIER_PATTERN.matcher(parentDirName); 66 if (!matcher.find()) { 67 throw new IllegalStateException(parentDirName); 68 } 69 String qualifiers = matcher.group(1); 70 return parse(qualifiers != null ? qualifiers : ""); 71 } 72 } 73 74 /** 75 * @deprecated Use {@link android.os.Build.VERSION#SDK_INT} instead. 76 */ 77 @Deprecated getPlatformVersion(String qualifiers)78 public static int getPlatformVersion(String qualifiers) { 79 Matcher m = VERSION_QUALIFIER_PATTERN.matcher(qualifiers); 80 if (m.find()) { 81 return Integer.parseInt(m.group(2)); 82 } 83 return -1; 84 } 85 86 /** 87 * @deprecated Use {@link android.content.res.Configuration#smallestScreenWidthDp} instead. 88 */ 89 @Deprecated getSmallestScreenWidth(String qualifiers)90 public static int getSmallestScreenWidth(String qualifiers) { 91 for (String qualifier : qualifiers.split("-", 0)) { 92 Matcher matcher = SMALLEST_SCREEN_WIDTH_PATTERN.matcher(qualifier); 93 if (matcher.find()) { 94 return Integer.parseInt(matcher.group(1)); 95 } 96 } 97 98 return -1; 99 } 100 101 /** 102 * If the Config already has a {@code sw} qualifier, do nothing. Otherwise, add a {@code sw} 103 * qualifier for the given width. 104 * 105 * @deprecated Use {@link android.content.res.Configuration#smallestScreenWidthDp} instead. 106 */ 107 @Deprecated addSmallestScreenWidth(String qualifiers, int smallestScreenWidth)108 public static String addSmallestScreenWidth(String qualifiers, int smallestScreenWidth) { 109 int qualifiersSmallestScreenWidth = Qualifiers.getSmallestScreenWidth(qualifiers); 110 if (qualifiersSmallestScreenWidth == -1) { 111 if (qualifiers.length() > 0) { 112 qualifiers += "-"; 113 } 114 qualifiers += "sw" + smallestScreenWidth + "dp"; 115 } 116 return qualifiers; 117 } 118 119 /** 120 * @deprecated Use {@link android.content.res.Configuration#screenWidthDp} instead. 121 */ 122 @Deprecated getScreenWidth(String qualifiers)123 public static int getScreenWidth(String qualifiers) { 124 for (String qualifier : qualifiers.split("-", 0)) { 125 Matcher matcher = SCREEN_WIDTH_PATTERN.matcher(qualifier); 126 if (matcher.find()) { 127 return Integer.parseInt(matcher.group(1)); 128 } 129 } 130 131 return -1; 132 } 133 134 /** 135 * @deprecated Use {@link android.content.res.Configuration#screenWidthDp} instead. 136 */ 137 @Deprecated addScreenWidth(String qualifiers, int screenWidth)138 public static String addScreenWidth(String qualifiers, int screenWidth) { 139 int qualifiersScreenWidth = Qualifiers.getScreenWidth(qualifiers); 140 if (qualifiersScreenWidth == -1) { 141 if (qualifiers.length() > 0) { 142 qualifiers += "-"; 143 } 144 qualifiers += "w" + screenWidth + "dp"; 145 } 146 return qualifiers; 147 } 148 149 /** 150 * @deprecated Use {@link android.content.res.Configuration#orientation} instead. 151 */ 152 @Deprecated getOrientation(String qualifiers)153 public static String getOrientation(String qualifiers) { 154 for (String qualifier : qualifiers.split("-", 0)) { 155 Matcher matcher = ORIENTATION_QUALIFIER_PATTERN.matcher(qualifier); 156 if (matcher.find()) { 157 return matcher.group(1); 158 } 159 } 160 return null; 161 } 162 } 163