ConfigDescription.cpp revision 6425497f4129a40e75569328525c0dcbaa6e3f22
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "ConfigDescription.h"
18#include "Locale.h"
19#include "SdkConstants.h"
20#include "util/StringPiece.h"
21#include "util/Util.h"
22
23#include <androidfw/ResourceTypes.h>
24#include <string>
25#include <vector>
26
27namespace aapt {
28
29using android::ResTable_config;
30
31static const char* kWildcardName = "any";
32
33static bool parseMcc(const char* name, ResTable_config* out) {
34    if (strcmp(name, kWildcardName) == 0) {
35        if (out) out->mcc = 0;
36        return true;
37    }
38    const char* c = name;
39    if (tolower(*c) != 'm') return false;
40    c++;
41    if (tolower(*c) != 'c') return false;
42    c++;
43    if (tolower(*c) != 'c') return false;
44    c++;
45
46    const char* val = c;
47
48    while (*c >= '0' && *c <= '9') {
49        c++;
50    }
51    if (*c != 0) return false;
52    if (c-val != 3) return false;
53
54    int d = atoi(val);
55    if (d != 0) {
56        if (out) out->mcc = d;
57        return true;
58    }
59
60    return false;
61}
62
63static bool parseMnc(const char* name, ResTable_config* out) {
64    if (strcmp(name, kWildcardName) == 0) {
65        if (out) out->mcc = 0;
66        return true;
67    }
68    const char* c = name;
69    if (tolower(*c) != 'm') return false;
70    c++;
71    if (tolower(*c) != 'n') return false;
72    c++;
73    if (tolower(*c) != 'c') return false;
74    c++;
75
76    const char* val = c;
77
78    while (*c >= '0' && *c <= '9') {
79        c++;
80    }
81    if (*c != 0) return false;
82    if (c-val == 0 || c-val > 3) return false;
83
84    if (out) {
85        out->mnc = atoi(val);
86        if (out->mnc == 0) {
87            out->mnc = ACONFIGURATION_MNC_ZERO;
88        }
89    }
90
91    return true;
92}
93
94static bool parseLayoutDirection(const char* name, ResTable_config* out) {
95    if (strcmp(name, kWildcardName) == 0) {
96        if (out) out->screenLayout =
97                (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
98                | ResTable_config::LAYOUTDIR_ANY;
99        return true;
100    } else if (strcmp(name, "ldltr") == 0) {
101        if (out) out->screenLayout =
102                (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
103                | ResTable_config::LAYOUTDIR_LTR;
104        return true;
105    } else if (strcmp(name, "ldrtl") == 0) {
106        if (out) out->screenLayout =
107                (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
108                | ResTable_config::LAYOUTDIR_RTL;
109        return true;
110    }
111
112    return false;
113}
114
115static bool parseScreenLayoutSize(const char* name, ResTable_config* out) {
116    if (strcmp(name, kWildcardName) == 0) {
117        if (out) out->screenLayout =
118                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
119                | ResTable_config::SCREENSIZE_ANY;
120        return true;
121    } else if (strcmp(name, "small") == 0) {
122        if (out) out->screenLayout =
123                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
124                | ResTable_config::SCREENSIZE_SMALL;
125        return true;
126    } else if (strcmp(name, "normal") == 0) {
127        if (out) out->screenLayout =
128                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
129                | ResTable_config::SCREENSIZE_NORMAL;
130        return true;
131    } else if (strcmp(name, "large") == 0) {
132        if (out) out->screenLayout =
133                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
134                | ResTable_config::SCREENSIZE_LARGE;
135        return true;
136    } else if (strcmp(name, "xlarge") == 0) {
137        if (out) out->screenLayout =
138                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
139                | ResTable_config::SCREENSIZE_XLARGE;
140        return true;
141    }
142
143    return false;
144}
145
146static bool parseScreenLayoutLong(const char* name, ResTable_config* out) {
147    if (strcmp(name, kWildcardName) == 0) {
148        if (out) out->screenLayout =
149                (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
150                | ResTable_config::SCREENLONG_ANY;
151        return true;
152    } else if (strcmp(name, "long") == 0) {
153        if (out) out->screenLayout =
154                (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
155                | ResTable_config::SCREENLONG_YES;
156        return true;
157    } else if (strcmp(name, "notlong") == 0) {
158        if (out) out->screenLayout =
159                (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
160                | ResTable_config::SCREENLONG_NO;
161        return true;
162    }
163
164    return false;
165}
166
167static bool parseScreenRound(const char* name, ResTable_config* out) {
168    if (strcmp(name, kWildcardName) == 0) {
169        if (out) out->screenLayout2 =
170                (out->screenLayout2&~ResTable_config::MASK_SCREENROUND)
171                | ResTable_config::SCREENROUND_ANY;
172        return true;
173    } else if (strcmp(name, "round") == 0) {
174        if (out) out->screenLayout2 =
175                (out->screenLayout2&~ResTable_config::MASK_SCREENROUND)
176                | ResTable_config::SCREENROUND_YES;
177        return true;
178    } else if (strcmp(name, "notround") == 0) {
179        if (out) out->screenLayout2 =
180                (out->screenLayout2&~ResTable_config::MASK_SCREENROUND)
181                | ResTable_config::SCREENROUND_NO;
182        return true;
183    }
184    return false;
185}
186
187static bool parseOrientation(const char* name, ResTable_config* out) {
188    if (strcmp(name, kWildcardName) == 0) {
189        if (out) out->orientation = out->ORIENTATION_ANY;
190        return true;
191    } else if (strcmp(name, "port") == 0) {
192        if (out) out->orientation = out->ORIENTATION_PORT;
193        return true;
194    } else if (strcmp(name, "land") == 0) {
195        if (out) out->orientation = out->ORIENTATION_LAND;
196        return true;
197    } else if (strcmp(name, "square") == 0) {
198        if (out) out->orientation = out->ORIENTATION_SQUARE;
199        return true;
200    }
201
202    return false;
203}
204
205static bool parseUiModeType(const char* name, ResTable_config* out) {
206    if (strcmp(name, kWildcardName) == 0) {
207        if (out) out->uiMode =
208                (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
209                | ResTable_config::UI_MODE_TYPE_ANY;
210        return true;
211    } else if (strcmp(name, "desk") == 0) {
212      if (out) out->uiMode =
213              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
214              | ResTable_config::UI_MODE_TYPE_DESK;
215        return true;
216    } else if (strcmp(name, "car") == 0) {
217      if (out) out->uiMode =
218              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
219              | ResTable_config::UI_MODE_TYPE_CAR;
220        return true;
221    } else if (strcmp(name, "television") == 0) {
222      if (out) out->uiMode =
223              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
224              | ResTable_config::UI_MODE_TYPE_TELEVISION;
225        return true;
226    } else if (strcmp(name, "appliance") == 0) {
227      if (out) out->uiMode =
228              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
229              | ResTable_config::UI_MODE_TYPE_APPLIANCE;
230        return true;
231    } else if (strcmp(name, "watch") == 0) {
232      if (out) out->uiMode =
233              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
234              | ResTable_config::UI_MODE_TYPE_WATCH;
235        return true;
236    }
237
238    return false;
239}
240
241static bool parseUiModeNight(const char* name, ResTable_config* out) {
242    if (strcmp(name, kWildcardName) == 0) {
243        if (out) out->uiMode =
244                (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
245                | ResTable_config::UI_MODE_NIGHT_ANY;
246        return true;
247    } else if (strcmp(name, "night") == 0) {
248        if (out) out->uiMode =
249                (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
250                | ResTable_config::UI_MODE_NIGHT_YES;
251        return true;
252    } else if (strcmp(name, "notnight") == 0) {
253      if (out) out->uiMode =
254              (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
255              | ResTable_config::UI_MODE_NIGHT_NO;
256        return true;
257    }
258
259    return false;
260}
261
262static bool parseDensity(const char* name, ResTable_config* out) {
263    if (strcmp(name, kWildcardName) == 0) {
264        if (out) out->density = ResTable_config::DENSITY_DEFAULT;
265        return true;
266    }
267
268    if (strcmp(name, "anydpi") == 0) {
269        if (out) out->density = ResTable_config::DENSITY_ANY;
270        return true;
271    }
272
273    if (strcmp(name, "nodpi") == 0) {
274        if (out) out->density = ResTable_config::DENSITY_NONE;
275        return true;
276    }
277
278    if (strcmp(name, "ldpi") == 0) {
279        if (out) out->density = ResTable_config::DENSITY_LOW;
280        return true;
281    }
282
283    if (strcmp(name, "mdpi") == 0) {
284        if (out) out->density = ResTable_config::DENSITY_MEDIUM;
285        return true;
286    }
287
288    if (strcmp(name, "tvdpi") == 0) {
289        if (out) out->density = ResTable_config::DENSITY_TV;
290        return true;
291    }
292
293    if (strcmp(name, "hdpi") == 0) {
294        if (out) out->density = ResTable_config::DENSITY_HIGH;
295        return true;
296    }
297
298    if (strcmp(name, "xhdpi") == 0) {
299        if (out) out->density = ResTable_config::DENSITY_XHIGH;
300        return true;
301    }
302
303    if (strcmp(name, "xxhdpi") == 0) {
304        if (out) out->density = ResTable_config::DENSITY_XXHIGH;
305        return true;
306    }
307
308    if (strcmp(name, "xxxhdpi") == 0) {
309        if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
310        return true;
311    }
312
313    char* c = (char*)name;
314    while (*c >= '0' && *c <= '9') {
315        c++;
316    }
317
318    // check that we have 'dpi' after the last digit.
319    if (toupper(c[0]) != 'D' ||
320            toupper(c[1]) != 'P' ||
321            toupper(c[2]) != 'I' ||
322            c[3] != 0) {
323        return false;
324    }
325
326    // temporarily replace the first letter with \0 to
327    // use atoi.
328    char tmp = c[0];
329    c[0] = '\0';
330
331    int d = atoi(name);
332    c[0] = tmp;
333
334    if (d != 0) {
335        if (out) out->density = d;
336        return true;
337    }
338
339    return false;
340}
341
342static bool parseTouchscreen(const char* name, ResTable_config* out) {
343    if (strcmp(name, kWildcardName) == 0) {
344        if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
345        return true;
346    } else if (strcmp(name, "notouch") == 0) {
347        if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
348        return true;
349    } else if (strcmp(name, "stylus") == 0) {
350        if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
351        return true;
352    } else if (strcmp(name, "finger") == 0) {
353        if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
354        return true;
355    }
356
357    return false;
358}
359
360static bool parseKeysHidden(const char* name, ResTable_config* out) {
361    uint8_t mask = 0;
362    uint8_t value = 0;
363    if (strcmp(name, kWildcardName) == 0) {
364        mask = ResTable_config::MASK_KEYSHIDDEN;
365        value = ResTable_config::KEYSHIDDEN_ANY;
366    } else if (strcmp(name, "keysexposed") == 0) {
367        mask = ResTable_config::MASK_KEYSHIDDEN;
368        value = ResTable_config::KEYSHIDDEN_NO;
369    } else if (strcmp(name, "keyshidden") == 0) {
370        mask = ResTable_config::MASK_KEYSHIDDEN;
371        value = ResTable_config::KEYSHIDDEN_YES;
372    } else if (strcmp(name, "keyssoft") == 0) {
373        mask = ResTable_config::MASK_KEYSHIDDEN;
374        value = ResTable_config::KEYSHIDDEN_SOFT;
375    }
376
377    if (mask != 0) {
378        if (out) out->inputFlags = (out->inputFlags&~mask) | value;
379        return true;
380    }
381
382    return false;
383}
384
385static bool parseKeyboard(const char* name, ResTable_config* out) {
386    if (strcmp(name, kWildcardName) == 0) {
387        if (out) out->keyboard = out->KEYBOARD_ANY;
388        return true;
389    } else if (strcmp(name, "nokeys") == 0) {
390        if (out) out->keyboard = out->KEYBOARD_NOKEYS;
391        return true;
392    } else if (strcmp(name, "qwerty") == 0) {
393        if (out) out->keyboard = out->KEYBOARD_QWERTY;
394        return true;
395    } else if (strcmp(name, "12key") == 0) {
396        if (out) out->keyboard = out->KEYBOARD_12KEY;
397        return true;
398    }
399
400    return false;
401}
402
403static bool parseNavHidden(const char* name, ResTable_config* out) {
404    uint8_t mask = 0;
405    uint8_t value = 0;
406    if (strcmp(name, kWildcardName) == 0) {
407        mask = ResTable_config::MASK_NAVHIDDEN;
408        value = ResTable_config::NAVHIDDEN_ANY;
409    } else if (strcmp(name, "navexposed") == 0) {
410        mask = ResTable_config::MASK_NAVHIDDEN;
411        value = ResTable_config::NAVHIDDEN_NO;
412    } else if (strcmp(name, "navhidden") == 0) {
413        mask = ResTable_config::MASK_NAVHIDDEN;
414        value = ResTable_config::NAVHIDDEN_YES;
415    }
416
417    if (mask != 0) {
418        if (out) out->inputFlags = (out->inputFlags&~mask) | value;
419        return true;
420    }
421
422    return false;
423}
424
425static bool parseNavigation(const char* name, ResTable_config* out) {
426    if (strcmp(name, kWildcardName) == 0) {
427        if (out) out->navigation = out->NAVIGATION_ANY;
428        return true;
429    } else if (strcmp(name, "nonav") == 0) {
430        if (out) out->navigation = out->NAVIGATION_NONAV;
431        return true;
432    } else if (strcmp(name, "dpad") == 0) {
433        if (out) out->navigation = out->NAVIGATION_DPAD;
434        return true;
435    } else if (strcmp(name, "trackball") == 0) {
436        if (out) out->navigation = out->NAVIGATION_TRACKBALL;
437        return true;
438    } else if (strcmp(name, "wheel") == 0) {
439        if (out) out->navigation = out->NAVIGATION_WHEEL;
440        return true;
441    }
442
443    return false;
444}
445
446static bool parseScreenSize(const char* name, ResTable_config* out) {
447    if (strcmp(name, kWildcardName) == 0) {
448        if (out) {
449            out->screenWidth = out->SCREENWIDTH_ANY;
450            out->screenHeight = out->SCREENHEIGHT_ANY;
451        }
452        return true;
453    }
454
455    const char* x = name;
456    while (*x >= '0' && *x <= '9') x++;
457    if (x == name || *x != 'x') return false;
458    std::string xName(name, x-name);
459    x++;
460
461    const char* y = x;
462    while (*y >= '0' && *y <= '9') y++;
463    if (y == name || *y != 0) return false;
464    std::string yName(x, y-x);
465
466    uint16_t w = (uint16_t)atoi(xName.c_str());
467    uint16_t h = (uint16_t)atoi(yName.c_str());
468    if (w < h) {
469        return false;
470    }
471
472    if (out) {
473        out->screenWidth = w;
474        out->screenHeight = h;
475    }
476
477    return true;
478}
479
480static bool parseSmallestScreenWidthDp(const char* name, ResTable_config* out) {
481    if (strcmp(name, kWildcardName) == 0) {
482        if (out) {
483            out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
484        }
485        return true;
486    }
487
488    if (*name != 's') return false;
489    name++;
490    if (*name != 'w') return false;
491    name++;
492    const char* x = name;
493    while (*x >= '0' && *x <= '9') x++;
494    if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
495    std::string xName(name, x-name);
496
497    if (out) {
498        out->smallestScreenWidthDp = (uint16_t)atoi(xName.c_str());
499    }
500
501    return true;
502}
503
504static bool parseScreenWidthDp(const char* name, ResTable_config* out) {
505    if (strcmp(name, kWildcardName) == 0) {
506        if (out) {
507            out->screenWidthDp = out->SCREENWIDTH_ANY;
508        }
509        return true;
510    }
511
512    if (*name != 'w') return false;
513    name++;
514    const char* x = name;
515    while (*x >= '0' && *x <= '9') x++;
516    if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
517    std::string xName(name, x-name);
518
519    if (out) {
520        out->screenWidthDp = (uint16_t)atoi(xName.c_str());
521    }
522
523    return true;
524}
525
526static bool parseScreenHeightDp(const char* name, ResTable_config* out) {
527    if (strcmp(name, kWildcardName) == 0) {
528        if (out) {
529            out->screenHeightDp = out->SCREENWIDTH_ANY;
530        }
531        return true;
532    }
533
534    if (*name != 'h') return false;
535    name++;
536    const char* x = name;
537    while (*x >= '0' && *x <= '9') x++;
538    if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
539    std::string xName(name, x-name);
540
541    if (out) {
542        out->screenHeightDp = (uint16_t)atoi(xName.c_str());
543    }
544
545    return true;
546}
547
548static bool parseVersion(const char* name, ResTable_config* out) {
549    if (strcmp(name, kWildcardName) == 0) {
550        if (out) {
551            out->sdkVersion = out->SDKVERSION_ANY;
552            out->minorVersion = out->MINORVERSION_ANY;
553        }
554        return true;
555    }
556
557    if (*name != 'v') {
558        return false;
559    }
560
561    name++;
562    const char* s = name;
563    while (*s >= '0' && *s <= '9') s++;
564    if (s == name || *s != 0) return false;
565    std::string sdkName(name, s-name);
566
567    if (out) {
568        out->sdkVersion = (uint16_t)atoi(sdkName.c_str());
569        out->minorVersion = 0;
570    }
571
572    return true;
573}
574
575bool ConfigDescription::parse(const StringPiece& str, ConfigDescription* out) {
576    std::vector<std::string> parts = util::splitAndLowercase(str, '-');
577
578    ConfigDescription config;
579    ssize_t partsConsumed = 0;
580    LocaleValue locale;
581
582    const auto partsEnd = parts.end();
583    auto partIter = parts.begin();
584
585    if (str.size() == 0) {
586        goto success;
587    }
588
589    if (parseMcc(partIter->c_str(), &config)) {
590        ++partIter;
591        if (partIter == partsEnd) {
592            goto success;
593        }
594    }
595
596    if (parseMnc(partIter->c_str(), &config)) {
597        ++partIter;
598        if (partIter == partsEnd) {
599            goto success;
600        }
601    }
602
603    // Locale spans a few '-' separators, so we let it
604    // control the index.
605    partsConsumed = locale.initFromParts(partIter, partsEnd);
606    if (partsConsumed < 0) {
607        return false;
608    } else {
609        locale.writeTo(&config);
610        partIter += partsConsumed;
611        if (partIter == partsEnd) {
612            goto success;
613        }
614    }
615
616    if (parseLayoutDirection(partIter->c_str(), &config)) {
617        ++partIter;
618        if (partIter == partsEnd) {
619            goto success;
620        }
621    }
622
623    if (parseSmallestScreenWidthDp(partIter->c_str(), &config)) {
624        ++partIter;
625        if (partIter == partsEnd) {
626            goto success;
627        }
628    }
629
630    if (parseScreenWidthDp(partIter->c_str(), &config)) {
631        ++partIter;
632        if (partIter == partsEnd) {
633            goto success;
634        }
635    }
636
637    if (parseScreenHeightDp(partIter->c_str(), &config)) {
638        ++partIter;
639        if (partIter == partsEnd) {
640            goto success;
641        }
642    }
643
644    if (parseScreenLayoutSize(partIter->c_str(), &config)) {
645        ++partIter;
646        if (partIter == partsEnd) {
647            goto success;
648        }
649    }
650
651    if (parseScreenLayoutLong(partIter->c_str(), &config)) {
652        ++partIter;
653        if (partIter == partsEnd) {
654            goto success;
655        }
656    }
657
658    if (parseScreenRound(partIter->c_str(), &config)) {
659        ++partIter;
660        if (partIter == partsEnd) {
661            goto success;
662        }
663    }
664
665    if (parseOrientation(partIter->c_str(), &config)) {
666        ++partIter;
667        if (partIter == partsEnd) {
668            goto success;
669        }
670    }
671
672    if (parseUiModeType(partIter->c_str(), &config)) {
673        ++partIter;
674        if (partIter == partsEnd) {
675            goto success;
676        }
677    }
678
679    if (parseUiModeNight(partIter->c_str(), &config)) {
680        ++partIter;
681        if (partIter == partsEnd) {
682            goto success;
683        }
684    }
685
686    if (parseDensity(partIter->c_str(), &config)) {
687        ++partIter;
688        if (partIter == partsEnd) {
689            goto success;
690        }
691    }
692
693    if (parseTouchscreen(partIter->c_str(), &config)) {
694        ++partIter;
695        if (partIter == partsEnd) {
696            goto success;
697        }
698    }
699
700    if (parseKeysHidden(partIter->c_str(), &config)) {
701        ++partIter;
702        if (partIter == partsEnd) {
703            goto success;
704        }
705    }
706
707    if (parseKeyboard(partIter->c_str(), &config)) {
708        ++partIter;
709        if (partIter == partsEnd) {
710            goto success;
711        }
712    }
713
714    if (parseNavHidden(partIter->c_str(), &config)) {
715        ++partIter;
716        if (partIter == partsEnd) {
717            goto success;
718        }
719    }
720
721    if (parseNavigation(partIter->c_str(), &config)) {
722        ++partIter;
723        if (partIter == partsEnd) {
724            goto success;
725        }
726    }
727
728    if (parseScreenSize(partIter->c_str(), &config)) {
729        ++partIter;
730        if (partIter == partsEnd) {
731            goto success;
732        }
733    }
734
735    if (parseVersion(partIter->c_str(), &config)) {
736        ++partIter;
737        if (partIter == partsEnd) {
738            goto success;
739        }
740    }
741
742    // Unrecognized.
743    return false;
744
745success:
746    if (out != NULL) {
747        applyVersionForCompatibility(&config);
748        *out = config;
749    }
750    return true;
751}
752
753void ConfigDescription::applyVersionForCompatibility(ConfigDescription* config) {
754    uint16_t minSdk = 0;
755    if (config->screenLayout2 & ResTable_config::MASK_SCREENROUND) {
756        minSdk = SDK_MARSHMALLOW;
757    } else if (config->density == ResTable_config::DENSITY_ANY) {
758        minSdk = SDK_LOLLIPOP;
759    } else if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
760            || config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY
761            || config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
762        minSdk = SDK_HONEYCOMB_MR2;
763    } else if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
764                != ResTable_config::UI_MODE_TYPE_ANY
765            ||  (config->uiMode & ResTable_config::MASK_UI_MODE_NIGHT)
766                != ResTable_config::UI_MODE_NIGHT_ANY) {
767        minSdk = SDK_FROYO;
768    } else if ((config->screenLayout & ResTable_config::MASK_SCREENSIZE)
769                != ResTable_config::SCREENSIZE_ANY
770            ||  (config->screenLayout & ResTable_config::MASK_SCREENLONG)
771                != ResTable_config::SCREENLONG_ANY
772            || config->density != ResTable_config::DENSITY_DEFAULT) {
773        minSdk = SDK_DONUT;
774    }
775
776    if (minSdk > config->sdkVersion) {
777        config->sdkVersion = minSdk;
778    }
779}
780
781} // namespace aapt
782