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