1package org.robolectric.res;
2
3import java.util.regex.Matcher;
4import java.util.regex.Pattern;
5import org.robolectric.res.android.ConfigDescription;
6import 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 */
11public 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
24  public static Qualifiers parse(String qualifiers) {
25    return parse(qualifiers, true);
26  }
27
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    }
34
35    return new Qualifiers(qualifiers, config);
36  }
37
38  protected Qualifiers(String qualifiers, ResTable_config config) {
39    this.qualifiers = qualifiers;
40    this.config = config;
41  }
42
43  public ResTable_config getConfig() {
44    return config;
45  }
46
47  @Override
48  public String toString() {
49    return qualifiers;
50  }
51
52  public static Qualifiers fromParentDir(FsFile parentDir) {
53    if (parentDir == null) {
54      return parse("");
55    } else {
56      String parentDirName = parentDir.getName();
57      Matcher matcher = DIR_QUALIFIER_PATTERN.matcher(parentDirName);
58      if (!matcher.find()) throw new IllegalStateException(parentDirName);
59      String qualifiers = matcher.group(1);
60      return parse(qualifiers != null ? qualifiers : "");
61    }
62  }
63
64  /**
65   * @deprecated Use {@link android.os.Build.VERSION#SDK_INT} instead.
66   */
67  @Deprecated
68  public static int getPlatformVersion(String qualifiers) {
69    Matcher m = VERSION_QUALIFIER_PATTERN.matcher(qualifiers);
70    if (m.find()) {
71      return Integer.parseInt(m.group(2));
72    }
73    return -1;
74  }
75
76  /**
77   * @deprecated Use {@link android.content.res.Configuration#smallestScreenWidthDp} instead.
78   */
79  @Deprecated
80  public static int getSmallestScreenWidth(String qualifiers) {
81    for (String qualifier : qualifiers.split("-")) {
82      Matcher matcher = SMALLEST_SCREEN_WIDTH_PATTERN.matcher(qualifier);
83      if (matcher.find()) {
84        return Integer.parseInt(matcher.group(1));
85      }
86    }
87
88    return -1;
89  }
90
91  /**
92   * If the Config already has a version qualifier, do nothing. Otherwise, add a version
93   * qualifier for the target api level (which comes from the manifest or Config.sdk()).
94   *
95   * @deprecated Figure something else out.
96   */
97  @Deprecated
98  public static String addPlatformVersion(String qualifiers, int apiLevel) {
99    int versionQualifierApiLevel = Qualifiers.getPlatformVersion(qualifiers);
100    if (versionQualifierApiLevel == -1) {
101      if (qualifiers.length() > 0) {
102        qualifiers += "-";
103      }
104      qualifiers += "v" + apiLevel;
105    }
106    return qualifiers;
107  }
108
109  /**
110   * If the Config already has a `sw` qualifier, do nothing. Otherwise, add a `sw`
111   * qualifier for the given width.
112   *
113   * @deprecated Use {@link android.content.res.Configuration#smallestScreenWidthDp} instead.
114   */
115  @Deprecated
116  public static String addSmallestScreenWidth(String qualifiers, int smallestScreenWidth) {
117    int qualifiersSmallestScreenWidth = Qualifiers.getSmallestScreenWidth(qualifiers);
118    if (qualifiersSmallestScreenWidth == -1) {
119      if (qualifiers.length() > 0) {
120        qualifiers += "-";
121      }
122      qualifiers += "sw" + smallestScreenWidth + "dp";
123    }
124    return qualifiers;
125  }
126
127  /**
128   * @deprecated Use {@link android.content.res.Configuration#screenWidthDp} instead.
129   */
130  @Deprecated
131  public static int getScreenWidth(String qualifiers) {
132    for (String qualifier : qualifiers.split("-")) {
133      Matcher matcher = SCREEN_WIDTH_PATTERN.matcher(qualifier);
134      if (matcher.find()) {
135        return Integer.parseInt(matcher.group(1));
136      }
137    }
138
139    return -1;
140  }
141
142  /**
143   * @deprecated Use {@link android.content.res.Configuration#screenWidthDp} instead.
144   */
145  @Deprecated
146  public static String addScreenWidth(String qualifiers, int screenWidth) {
147    int qualifiersScreenWidth = Qualifiers.getScreenWidth(qualifiers);
148    if (qualifiersScreenWidth == -1) {
149      if (qualifiers.length() > 0) {
150        qualifiers += "-";
151      }
152      qualifiers += "w" + screenWidth + "dp";
153    }
154    return qualifiers;
155  }
156
157  /**
158   * @deprecated Use {@link android.content.res.Configuration#orientation} instead.
159   */
160  @Deprecated
161  public static String getOrientation(String qualifiers) {
162    for (String qualifier : qualifiers.split("-")) {
163      Matcher matcher = ORIENTATION_QUALIFIER_PATTERN.matcher(qualifier);
164      if (matcher.find()) {
165        return matcher.group(1);
166      }
167    }
168    return null;
169  }
170}
171