1 /*
2  * Copyright (C) 2008 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 package android.content.res;
18 
19 import static android.content.ConfigurationProto.COLOR_MODE;
20 import static android.content.ConfigurationProto.DENSITY_DPI;
21 import static android.content.ConfigurationProto.FONT_SCALE;
22 import static android.content.ConfigurationProto.FONT_WEIGHT_ADJUSTMENT;
23 import static android.content.ConfigurationProto.GRAMMATICAL_GENDER;
24 import static android.content.ConfigurationProto.HARD_KEYBOARD_HIDDEN;
25 import static android.content.ConfigurationProto.KEYBOARD;
26 import static android.content.ConfigurationProto.KEYBOARD_HIDDEN;
27 import static android.content.ConfigurationProto.LOCALES;
28 import static android.content.ConfigurationProto.LOCALE_LIST;
29 import static android.content.ConfigurationProto.MCC;
30 import static android.content.ConfigurationProto.MNC;
31 import static android.content.ConfigurationProto.NAVIGATION;
32 import static android.content.ConfigurationProto.NAVIGATION_HIDDEN;
33 import static android.content.ConfigurationProto.ORIENTATION;
34 import static android.content.ConfigurationProto.SCREEN_HEIGHT_DP;
35 import static android.content.ConfigurationProto.SCREEN_LAYOUT;
36 import static android.content.ConfigurationProto.SCREEN_WIDTH_DP;
37 import static android.content.ConfigurationProto.SMALLEST_SCREEN_WIDTH_DP;
38 import static android.content.ConfigurationProto.TOUCHSCREEN;
39 import static android.content.ConfigurationProto.UI_MODE;
40 import static android.content.ConfigurationProto.WINDOW_CONFIGURATION;
41 import static android.content.ResourcesConfigurationProto.CONFIGURATION;
42 import static android.content.ResourcesConfigurationProto.SCREEN_HEIGHT_PX;
43 import static android.content.ResourcesConfigurationProto.SCREEN_WIDTH_PX;
44 import static android.content.ResourcesConfigurationProto.SDK_VERSION;
45 
46 import android.annotation.IntDef;
47 import android.annotation.NonNull;
48 import android.annotation.Nullable;
49 import android.annotation.TestApi;
50 import android.app.GrammaticalInflectionManager;
51 import android.app.WindowConfiguration;
52 import android.compat.annotation.UnsupportedAppUsage;
53 import android.content.LocaleProto;
54 import android.content.pm.ActivityInfo;
55 import android.content.pm.ActivityInfo.Config;
56 import android.graphics.Typeface;
57 import android.os.Build;
58 import android.os.LocaleList;
59 import android.os.Parcel;
60 import android.os.Parcelable;
61 import android.text.TextUtils;
62 import android.util.DisplayMetrics;
63 import android.util.Slog;
64 import android.util.proto.ProtoInputStream;
65 import android.util.proto.ProtoOutputStream;
66 import android.util.proto.WireTypeMismatchException;
67 import android.view.View;
68 
69 import com.android.internal.util.XmlUtils;
70 
71 import org.xmlpull.v1.XmlPullParser;
72 import org.xmlpull.v1.XmlPullParserException;
73 
74 import java.io.IOException;
75 import java.lang.annotation.Retention;
76 import java.lang.annotation.RetentionPolicy;
77 import java.util.ArrayList;
78 import java.util.IllformedLocaleException;
79 import java.util.List;
80 import java.util.Locale;
81 
82 /**
83  * This class describes all device configuration information that can
84  * impact the resources the application retrieves.  This includes both
85  * user-specified configuration options (locale list and scaling) as well
86  * as device configurations (such as input modes, screen size and screen orientation).
87  * <p>You can acquire this object from {@link Resources}, using {@link
88  * Resources#getConfiguration}. Thus, from an activity, you can get it by chaining the request
89  * with {@link android.app.Activity#getResources}:</p>
90  * <pre>Configuration config = getResources().getConfiguration();</pre>
91  */
92 public final class Configuration implements Parcelable, Comparable<Configuration> {
93     /** @hide */
94     public static final Configuration EMPTY = new Configuration();
95 
96     private static final String TAG = "Configuration";
97 
98     /**
99      * Current user preference for the scaling factor for fonts, relative
100      * to the base density scaling.
101      *
102      * <p>Note: Please do not use this to hardcode font size equations. The equation for font
103      * scaling is now non-linear; this coefficient is no longer used as a direct multiplier to
104      * determine font size. It exists for informational purposes only.
105      *
106      * <p>Please use {@link android.util.TypedValue#applyDimension(int, float, DisplayMetrics)} or
107      * {@link android.util.TypedValue#deriveDimension(int, float, DisplayMetrics)} to convert
108      * between scaled font size dimensions and pixels.
109      */
110     public float fontScale;
111 
112     /**
113      * IMSI MCC (Mobile Country Code), corresponding to
114      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mcc</a>
115      * resource qualifier.  0 if undefined.
116      */
117     public int mcc;
118 
119     /**
120      * IMSI MNC (Mobile Network Code), corresponding to
121      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mnc</a>
122      * resource qualifier.  0 if undefined. Note that the actual MNC may be 0; in order to check
123      * for this use the {@link #MNC_ZERO} symbol.
124      */
125     public int mnc;
126 
127     /**
128      * Constant used to to represent MNC (Mobile Network Code) zero.
129      * 0 cannot be used, since it is used to represent an undefined MNC.
130      */
131     public static final int MNC_ZERO = 0xffff;
132 
133     /**
134      * Current user preference for the locale, corresponding to
135      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a>
136      * resource qualifier.
137      *
138      * @deprecated Do not set or read this directly. Use {@link #getLocales()} and
139      * {@link #setLocales(LocaleList)}. If only the primary locale is needed,
140      * <code>getLocales().get(0)</code> is now the preferred accessor.
141      */
142     @Deprecated public Locale locale;
143 
144     private LocaleList mLocaleList;
145 
146     /**
147      * Locale should persist on setting.  This is hidden because it is really
148      * questionable whether this is the right way to expose the functionality.
149      * @hide
150      */
151     @UnsupportedAppUsage
152     public boolean userSetLocale;
153 
154     /**
155      * Current user preference for the grammatical gender.
156      */
157     private int mGrammaticalGender;
158 
159     /** @hide */
160     @IntDef(prefix = { "GRAMMATICAL_GENDER_" }, value = {
161             GRAMMATICAL_GENDER_NOT_SPECIFIED,
162             GRAMMATICAL_GENDER_NEUTRAL,
163             GRAMMATICAL_GENDER_FEMININE,
164             GRAMMATICAL_GENDER_MASCULINE,
165     })
166     @Retention(RetentionPolicy.SOURCE)
167     public @interface GrammaticalGender {}
168 
169     /**
170      * Constant for grammatical gender: to indicate that the grammatical gender is undefined.
171      * Only for internal usage.
172      * @hide
173      */
174     public static final int GRAMMATICAL_GENDER_UNDEFINED = -1;
175 
176     /**
177      * Constant for grammatical gender: to indicate the user has not specified the terms
178      * of address for the application.
179      */
180     public static final int GRAMMATICAL_GENDER_NOT_SPECIFIED = 0;
181 
182     /**
183      * Constant for grammatical gender: to indicate the terms of address the user
184      * preferred in an application is neuter.
185      */
186     public static final int GRAMMATICAL_GENDER_NEUTRAL = 1;
187 
188     /**
189      * Constant for grammatical gender: to indicate the terms of address the user
190          * preferred in an application is feminine.
191      */
192     public static final int GRAMMATICAL_GENDER_FEMININE = 2;
193 
194     /**
195      * Constant for grammatical gender: to indicate the terms of address the user
196      * preferred in an application is masculine.
197      */
198     public static final int GRAMMATICAL_GENDER_MASCULINE = 3;
199 
200     /** Constant for {@link #colorMode}: bits that encode whether the screen is wide gamut. */
201     public static final int COLOR_MODE_WIDE_COLOR_GAMUT_MASK = 0x3;
202     /**
203      * Constant for {@link #colorMode}: a {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} value
204      * indicating that it is unknown whether or not the screen is wide gamut.
205      */
206     public static final int COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED = 0x0;
207     /**
208      * Constant for {@link #colorMode}: a {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} value
209      * indicating that the screen is not wide gamut.
210      * <p>Corresponds to the <code>-nowidecg</code> resource qualifier.</p>
211      */
212     public static final int COLOR_MODE_WIDE_COLOR_GAMUT_NO = 0x1;
213     /**
214      * Constant for {@link #colorMode}: a {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} value
215      * indicating that the screen is wide gamut.
216      * <p>Corresponds to the <code>-widecg</code> resource qualifier.</p>
217      */
218     public static final int COLOR_MODE_WIDE_COLOR_GAMUT_YES = 0x2;
219 
220     /** Constant for {@link #colorMode}: bits that encode the dynamic range of the screen. */
221     public static final int COLOR_MODE_HDR_MASK = 0xc;
222     /** Constant for {@link #colorMode}: bits shift to get the screen dynamic range. */
223     public static final int COLOR_MODE_HDR_SHIFT = 2;
224     /**
225      * Constant for {@link #colorMode}: a {@link #COLOR_MODE_HDR_MASK} value
226      * indicating that it is unknown whether or not the screen is HDR.
227      */
228     public static final int COLOR_MODE_HDR_UNDEFINED = 0x0;
229     /**
230      * Constant for {@link #colorMode}: a {@link #COLOR_MODE_HDR_MASK} value
231      * indicating that the screen is not HDR (low/standard dynamic range).
232      * <p>Corresponds to the <code>-lowdr</code> resource qualifier.</p>
233      */
234     public static final int COLOR_MODE_HDR_NO = 0x1 << COLOR_MODE_HDR_SHIFT;
235     /**
236      * Constant for {@link #colorMode}: a {@link #COLOR_MODE_HDR_MASK} value
237      * indicating that the screen is HDR (dynamic range).
238      * <p>Corresponds to the <code>-highdr</code> resource qualifier.</p>
239      */
240     public static final int COLOR_MODE_HDR_YES = 0x2 << COLOR_MODE_HDR_SHIFT;
241 
242     /** Constant for {@link #colorMode}: a value indicating that the color mode is undefined */
243     @SuppressWarnings("PointlessBitwiseExpression")
244     public static final int COLOR_MODE_UNDEFINED = COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED |
245             COLOR_MODE_HDR_UNDEFINED;
246 
247     /**
248      * Bit mask of color capabilities of the screen. Currently there are two fields:
249      * <p>The {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} bits define the color gamut of
250      * the screen. They may be one of
251      * {@link #COLOR_MODE_WIDE_COLOR_GAMUT_NO} or {@link #COLOR_MODE_WIDE_COLOR_GAMUT_YES}.</p>
252      *
253      * <p>The {@link #COLOR_MODE_HDR_MASK} defines the dynamic range of the screen. They may be
254      * one of {@link #COLOR_MODE_HDR_NO} or {@link #COLOR_MODE_HDR_YES}.</p>
255      *
256      * <p>See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
257      * Multiple Screens</a> for more information.</p>
258      */
259     public int colorMode;
260 
261     /** Constant for {@link #screenLayout}: bits that encode the size. */
262     public static final int SCREENLAYOUT_SIZE_MASK = 0x0f;
263     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
264      * value indicating that no size has been set. */
265     public static final int SCREENLAYOUT_SIZE_UNDEFINED = 0x00;
266     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
267      * value indicating the screen is at least approximately 320x426 dp units,
268      * corresponds to the
269      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">small</a>
270      * resource qualifier.
271      * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
272      * Multiple Screens</a> for more information. */
273     public static final int SCREENLAYOUT_SIZE_SMALL = 0x01;
274     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
275      * value indicating the screen is at least approximately 320x470 dp units,
276      * corresponds to the
277      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">normal</a>
278      * resource qualifier.
279      * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
280      * Multiple Screens</a> for more information. */
281     public static final int SCREENLAYOUT_SIZE_NORMAL = 0x02;
282     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
283      * value indicating the screen is at least approximately 480x640 dp units,
284      * corresponds to the
285      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">large</a>
286      * resource qualifier.
287      * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
288      * Multiple Screens</a> for more information. */
289     public static final int SCREENLAYOUT_SIZE_LARGE = 0x03;
290     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
291      * value indicating the screen is at least approximately 720x960 dp units,
292      * corresponds to the
293      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">xlarge</a>
294      * resource qualifier.
295      * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
296      * Multiple Screens</a> for more information.*/
297     public static final int SCREENLAYOUT_SIZE_XLARGE = 0x04;
298 
299     /** Constant for {@link #screenLayout}: bits that encode the aspect ratio. */
300     public static final int SCREENLAYOUT_LONG_MASK = 0x30;
301     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK}
302      * value indicating that no size has been set. */
303     public static final int SCREENLAYOUT_LONG_UNDEFINED = 0x00;
304     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK}
305      * value that corresponds to the
306      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenAspectQualifier">notlong</a>
307      * resource qualifier. */
308     public static final int SCREENLAYOUT_LONG_NO = 0x10;
309     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK}
310      * value that corresponds to the
311      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenAspectQualifier">long</a>
312      * resource qualifier. */
313     public static final int SCREENLAYOUT_LONG_YES = 0x20;
314 
315     /** Constant for {@link #screenLayout}: bits that encode the layout direction. */
316     public static final int SCREENLAYOUT_LAYOUTDIR_MASK = 0xC0;
317     /** Constant for {@link #screenLayout}: bits shift to get the layout direction. */
318     public static final int SCREENLAYOUT_LAYOUTDIR_SHIFT = 6;
319     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK}
320      * value indicating that no layout dir has been set. */
321     public static final int SCREENLAYOUT_LAYOUTDIR_UNDEFINED = 0x00;
322     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK}
323      * value indicating that a layout dir has been set to LTR. */
324     public static final int SCREENLAYOUT_LAYOUTDIR_LTR = 0x01 << SCREENLAYOUT_LAYOUTDIR_SHIFT;
325     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK}
326      * value indicating that a layout dir has been set to RTL. */
327     public static final int SCREENLAYOUT_LAYOUTDIR_RTL = 0x02 << SCREENLAYOUT_LAYOUTDIR_SHIFT;
328 
329     /** Constant for {@link #screenLayout}: bits that encode roundness of the screen. */
330     public static final int SCREENLAYOUT_ROUND_MASK = 0x300;
331     /** @hide Constant for {@link #screenLayout}: bit shift to get to screen roundness bits */
332     public static final int SCREENLAYOUT_ROUND_SHIFT = 8;
333     /**
334      * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating
335      * that it is unknown whether or not the screen has a round shape.
336      */
337     public static final int SCREENLAYOUT_ROUND_UNDEFINED = 0x00;
338     /**
339      * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating
340      * that the screen does not have a rounded shape.
341      */
342     public static final int SCREENLAYOUT_ROUND_NO = 0x1 << SCREENLAYOUT_ROUND_SHIFT;
343     /**
344      * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating
345      * that the screen has a rounded shape. Corners may not be visible to the user;
346      * developers should pay special attention to the {@link android.view.WindowInsets} delivered
347      * to views for more information about ensuring content is not obscured.
348      *
349      * <p>Corresponds to the <code>-round</code> resource qualifier.</p>
350      */
351     public static final int SCREENLAYOUT_ROUND_YES = 0x2 << SCREENLAYOUT_ROUND_SHIFT;
352 
353     /** Constant for {@link #screenLayout}: a value indicating that screenLayout is undefined */
354     public static final int SCREENLAYOUT_UNDEFINED = SCREENLAYOUT_SIZE_UNDEFINED |
355             SCREENLAYOUT_LONG_UNDEFINED | SCREENLAYOUT_LAYOUTDIR_UNDEFINED |
356             SCREENLAYOUT_ROUND_UNDEFINED;
357 
358     /**
359      * Special flag we generate to indicate that the screen layout requires
360      * us to use a compatibility mode for apps that are not modern layout
361      * aware.
362      * @hide
363      */
364     public static final int SCREENLAYOUT_COMPAT_NEEDED = 0x10000000;
365 
366     /**
367      * Bit mask of overall layout of the screen.  Currently there are four
368      * fields:
369      * <p>The {@link #SCREENLAYOUT_SIZE_MASK} bits define the overall size
370      * of the screen.  They may be one of
371      * {@link #SCREENLAYOUT_SIZE_SMALL}, {@link #SCREENLAYOUT_SIZE_NORMAL},
372      * {@link #SCREENLAYOUT_SIZE_LARGE}, or {@link #SCREENLAYOUT_SIZE_XLARGE}.</p>
373      *
374      * <p>The {@link #SCREENLAYOUT_LONG_MASK} defines whether the screen
375      * is wider/taller than normal.  They may be one of
376      * {@link #SCREENLAYOUT_LONG_NO} or {@link #SCREENLAYOUT_LONG_YES}.</p>
377      *
378      * <p>The {@link #SCREENLAYOUT_LAYOUTDIR_MASK} defines whether the screen layout
379      * is either LTR or RTL.  They may be one of
380      * {@link #SCREENLAYOUT_LAYOUTDIR_LTR} or {@link #SCREENLAYOUT_LAYOUTDIR_RTL}.</p>
381      *
382      * <p>The {@link #SCREENLAYOUT_ROUND_MASK} defines whether the screen has a rounded
383      * shape. They may be one of {@link #SCREENLAYOUT_ROUND_NO} or {@link #SCREENLAYOUT_ROUND_YES}.
384      * </p>
385      *
386      * <p>See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
387      * Multiple Screens</a> for more information.</p>
388      */
389     public int screenLayout;
390 
391     /**
392      * An undefined fontWeightAdjustment.
393      */
394     public static final int FONT_WEIGHT_ADJUSTMENT_UNDEFINED = Integer.MAX_VALUE;
395 
396     /**
397      * Adjustment in text font weight. Used to reflect the current user preference for increasing
398      * font weight.
399      *
400      * <p> If the text font weight is less than the minimum of 1, 1 will be used. If the font weight
401      * exceeds the maximum of 1000, 1000 will be used.
402      *
403      * @see android.graphics.Typeface#create(Typeface, int, boolean)
404      * @see android.graphics.fonts.FontStyle#FONT_WEIGHT_MIN
405      * @see android.graphics.fonts.FontStyle#FONT_WEIGHT_MAX
406      */
407     public int fontWeightAdjustment;
408 
409     /**
410      * Configuration relating to the windowing state of the object associated with this
411      * Configuration. Contents of this field are not intended to affect resources, but need to be
412      * communicated and propagated at the same time as the rest of Configuration.
413      * @hide
414      */
415     @TestApi
416     public final WindowConfiguration windowConfiguration = new WindowConfiguration();
417 
418     /** @hide */
resetScreenLayout(int curLayout)419     static public int resetScreenLayout(int curLayout) {
420         return (curLayout&~(SCREENLAYOUT_LONG_MASK | SCREENLAYOUT_SIZE_MASK
421                         | SCREENLAYOUT_COMPAT_NEEDED))
422                 | (SCREENLAYOUT_LONG_YES | SCREENLAYOUT_SIZE_XLARGE);
423     }
424 
425     /** @hide */
reduceScreenLayout(int curLayout, int longSizeDp, int shortSizeDp)426     static public int reduceScreenLayout(int curLayout, int longSizeDp, int shortSizeDp) {
427         int screenLayoutSize;
428         boolean screenLayoutLong;
429         boolean screenLayoutCompatNeeded;
430 
431         // These semi-magic numbers define our compatibility modes for
432         // applications with different screens.  These are guarantees to
433         // app developers about the space they can expect for a particular
434         // configuration.  DO NOT CHANGE!
435         if (longSizeDp < 470) {
436             // This is shorter than an HVGA normal density screen (which
437             // is 480 pixels on its long side).
438             screenLayoutSize = SCREENLAYOUT_SIZE_SMALL;
439             screenLayoutLong = false;
440             screenLayoutCompatNeeded = false;
441         } else {
442             // What size is this screen screen?
443             if (longSizeDp >= 960 && shortSizeDp >= 720) {
444                 // 1.5xVGA or larger screens at medium density are the point
445                 // at which we consider it to be an extra large screen.
446                 screenLayoutSize = SCREENLAYOUT_SIZE_XLARGE;
447             } else if (longSizeDp >= 640 && shortSizeDp >= 480) {
448                 // VGA or larger screens at medium density are the point
449                 // at which we consider it to be a large screen.
450                 screenLayoutSize = SCREENLAYOUT_SIZE_LARGE;
451             } else {
452                 screenLayoutSize = SCREENLAYOUT_SIZE_NORMAL;
453             }
454 
455             // If this screen is wider than normal HVGA, or taller
456             // than FWVGA, then for old apps we want to run in size
457             // compatibility mode.
458             if (shortSizeDp > 321 || longSizeDp > 570) {
459                 screenLayoutCompatNeeded = true;
460             } else {
461                 screenLayoutCompatNeeded = false;
462             }
463 
464             // Is this a long screen?
465             if (((longSizeDp*3)/5) >= (shortSizeDp-1)) {
466                 // Anything wider than WVGA (5:3) is considering to be long.
467                 screenLayoutLong = true;
468             } else {
469                 screenLayoutLong = false;
470             }
471         }
472 
473         // Now reduce the last screenLayout to not be better than what we
474         // have found.
475         if (!screenLayoutLong) {
476             curLayout = (curLayout&~SCREENLAYOUT_LONG_MASK) | SCREENLAYOUT_LONG_NO;
477         }
478         if (screenLayoutCompatNeeded) {
479             curLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
480         }
481         int curSize = curLayout&SCREENLAYOUT_SIZE_MASK;
482         if (screenLayoutSize < curSize) {
483             curLayout = (curLayout&~SCREENLAYOUT_SIZE_MASK) | screenLayoutSize;
484         }
485         return curLayout;
486     }
487 
488     /** @hide */
configurationDiffToString(int diff)489     public static String configurationDiffToString(int diff) {
490         ArrayList<String> list = new ArrayList<>();
491         if ((diff & ActivityInfo.CONFIG_MCC) != 0) {
492             list.add("CONFIG_MCC");
493         }
494         if ((diff & ActivityInfo.CONFIG_MNC) != 0) {
495             list.add("CONFIG_MNC");
496         }
497         if ((diff & ActivityInfo.CONFIG_LOCALE) != 0) {
498             list.add("CONFIG_LOCALE");
499         }
500         if ((diff & ActivityInfo.CONFIG_TOUCHSCREEN) != 0) {
501             list.add("CONFIG_TOUCHSCREEN");
502         }
503         if ((diff & ActivityInfo.CONFIG_KEYBOARD) != 0) {
504             list.add("CONFIG_KEYBOARD");
505         }
506         if ((diff & ActivityInfo.CONFIG_KEYBOARD_HIDDEN) != 0) {
507             list.add("CONFIG_KEYBOARD_HIDDEN");
508         }
509         if ((diff & ActivityInfo.CONFIG_NAVIGATION) != 0) {
510             list.add("CONFIG_NAVIGATION");
511         }
512         if ((diff & ActivityInfo.CONFIG_ORIENTATION) != 0) {
513             list.add("CONFIG_ORIENTATION");
514         }
515         if ((diff & ActivityInfo.CONFIG_SCREEN_LAYOUT) != 0) {
516             list.add("CONFIG_SCREEN_LAYOUT");
517         }
518         if ((diff & ActivityInfo.CONFIG_COLOR_MODE) != 0) {
519             list.add("CONFIG_COLOR_MODE");
520         }
521         if ((diff & ActivityInfo.CONFIG_UI_MODE) != 0) {
522             list.add("CONFIG_UI_MODE");
523         }
524         if ((diff & ActivityInfo.CONFIG_SCREEN_SIZE) != 0) {
525             list.add("CONFIG_SCREEN_SIZE");
526         }
527         if ((diff & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0) {
528             list.add("CONFIG_SMALLEST_SCREEN_SIZE");
529         }
530         if ((diff & ActivityInfo.CONFIG_DENSITY) != 0) {
531             list.add("CONFIG_DENSITY");
532         }
533         if ((diff & ActivityInfo.CONFIG_LAYOUT_DIRECTION) != 0) {
534             list.add("CONFIG_LAYOUT_DIRECTION");
535         }
536         if ((diff & ActivityInfo.CONFIG_FONT_SCALE) != 0) {
537             list.add("CONFIG_FONT_SCALE");
538         }
539         if ((diff & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) {
540             list.add("CONFIG_ASSETS_PATHS");
541         }
542         if ((diff & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0) {
543             list.add("CONFIG_WINDOW_CONFIGURATION");
544         }
545         if ((diff & ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT) != 0) {
546             list.add("CONFIG_AUTO_BOLD_TEXT");
547         }
548         if ((diff & ActivityInfo.CONFIG_GRAMMATICAL_GENDER) != 0) {
549             list.add("CONFIG_GRAMMATICAL_GENDER");
550         }
551         return "{" + TextUtils.join(", ", list) + "}";
552     }
553 
554     /**
555      * Check if the Configuration's current {@link #screenLayout} is at
556      * least the given size.
557      *
558      * @param size The desired size, either {@link #SCREENLAYOUT_SIZE_SMALL},
559      * {@link #SCREENLAYOUT_SIZE_NORMAL}, {@link #SCREENLAYOUT_SIZE_LARGE}, or
560      * {@link #SCREENLAYOUT_SIZE_XLARGE}.
561      * @return Returns true if the current screen layout size is at least
562      * the given size.
563      */
isLayoutSizeAtLeast(int size)564     public boolean isLayoutSizeAtLeast(int size) {
565         int cur = screenLayout&SCREENLAYOUT_SIZE_MASK;
566         if (cur == SCREENLAYOUT_SIZE_UNDEFINED) return false;
567         return cur >= size;
568     }
569 
570     /** Constant for {@link #touchscreen}: a value indicating that no value has been set. */
571     public static final int TOUCHSCREEN_UNDEFINED = 0;
572     /** Constant for {@link #touchscreen}, value corresponding to the
573      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#TouchscreenQualifier">notouch</a>
574      * resource qualifier. */
575     public static final int TOUCHSCREEN_NOTOUCH = 1;
576     /** @deprecated Not currently supported or used. */
577     @Deprecated public static final int TOUCHSCREEN_STYLUS = 2;
578     /** Constant for {@link #touchscreen}, value corresponding to the
579      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#TouchscreenQualifier">finger</a>
580      * resource qualifier. */
581     public static final int TOUCHSCREEN_FINGER = 3;
582 
583     /**
584      * The kind of touch screen attached to the device.
585      * One of: {@link #TOUCHSCREEN_NOTOUCH}, {@link #TOUCHSCREEN_FINGER}.
586      */
587     public int touchscreen;
588 
589     /** Constant for {@link #keyboard}: a value indicating that no value has been set. */
590     public static final int KEYBOARD_UNDEFINED = 0;
591     /** Constant for {@link #keyboard}, value corresponding to the
592      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">nokeys</a>
593      * resource qualifier. */
594     public static final int KEYBOARD_NOKEYS = 1;
595     /** Constant for {@link #keyboard}, value corresponding to the
596      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">qwerty</a>
597      * resource qualifier. */
598     public static final int KEYBOARD_QWERTY = 2;
599     /** Constant for {@link #keyboard}, value corresponding to the
600      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">12key</a>
601      * resource qualifier. */
602     public static final int KEYBOARD_12KEY = 3;
603 
604     /**
605      * The kind of keyboard attached to the device.
606      * One of: {@link #KEYBOARD_NOKEYS}, {@link #KEYBOARD_QWERTY},
607      * {@link #KEYBOARD_12KEY}.
608      */
609     public int keyboard;
610 
611     /** Constant for {@link #keyboardHidden}: a value indicating that no value has been set. */
612     public static final int KEYBOARDHIDDEN_UNDEFINED = 0;
613     /** Constant for {@link #keyboardHidden}, value corresponding to the
614      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keysexposed</a>
615      * resource qualifier. */
616     public static final int KEYBOARDHIDDEN_NO = 1;
617     /** Constant for {@link #keyboardHidden}, value corresponding to the
618      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keyshidden</a>
619      * resource qualifier. */
620     public static final int KEYBOARDHIDDEN_YES = 2;
621     /** Constant matching actual resource implementation. {@hide} */
622     public static final int KEYBOARDHIDDEN_SOFT = 3;
623 
624     /**
625      * A flag indicating whether any keyboard is available.  Unlike
626      * {@link #hardKeyboardHidden}, this also takes into account a soft
627      * keyboard, so if the hard keyboard is hidden but there is soft
628      * keyboard available, it will be set to NO.  Value is one of:
629      * {@link #KEYBOARDHIDDEN_NO}, {@link #KEYBOARDHIDDEN_YES}.
630      */
631     public int keyboardHidden;
632 
633     /** Constant for {@link #hardKeyboardHidden}: a value indicating that no value has been set. */
634     public static final int HARDKEYBOARDHIDDEN_UNDEFINED = 0;
635     /** Constant for {@link #hardKeyboardHidden}, value corresponding to the
636      * physical keyboard being exposed. */
637     public static final int HARDKEYBOARDHIDDEN_NO = 1;
638     /** Constant for {@link #hardKeyboardHidden}, value corresponding to the
639      * physical keyboard being hidden. */
640     public static final int HARDKEYBOARDHIDDEN_YES = 2;
641 
642     /**
643      * A flag indicating whether the hard keyboard has been hidden.  This will
644      * be set on a device with a mechanism to hide the keyboard from the
645      * user, when that mechanism is closed.  One of:
646      * {@link #HARDKEYBOARDHIDDEN_NO}, {@link #HARDKEYBOARDHIDDEN_YES}.
647      */
648     public int hardKeyboardHidden;
649 
650     /** Constant for {@link #navigation}: a value indicating that no value has been set. */
651     public static final int NAVIGATION_UNDEFINED = 0;
652     /** Constant for {@link #navigation}, value corresponding to the
653      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">nonav</a>
654      * resource qualifier. */
655     public static final int NAVIGATION_NONAV = 1;
656     /** Constant for {@link #navigation}, value corresponding to the
657      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">dpad</a>
658      * resource qualifier. */
659     public static final int NAVIGATION_DPAD = 2;
660     /** Constant for {@link #navigation}, value corresponding to the
661      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">trackball</a>
662      * resource qualifier. */
663     public static final int NAVIGATION_TRACKBALL = 3;
664     /** Constant for {@link #navigation}, value corresponding to the
665      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">wheel</a>
666      * resource qualifier. */
667     public static final int NAVIGATION_WHEEL = 4;
668 
669     /**
670      * The kind of navigation method available on the device.
671      * One of: {@link #NAVIGATION_NONAV}, {@link #NAVIGATION_DPAD},
672      * {@link #NAVIGATION_TRACKBALL}, {@link #NAVIGATION_WHEEL}.
673      */
674     public int navigation;
675 
676     /** Constant for {@link #navigationHidden}: a value indicating that no value has been set. */
677     public static final int NAVIGATIONHIDDEN_UNDEFINED = 0;
678     /** Constant for {@link #navigationHidden}, value corresponding to the
679      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavAvailQualifier">navexposed</a>
680      * resource qualifier. */
681     public static final int NAVIGATIONHIDDEN_NO = 1;
682     /** Constant for {@link #navigationHidden}, value corresponding to the
683      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavAvailQualifier">navhidden</a>
684      * resource qualifier. */
685     public static final int NAVIGATIONHIDDEN_YES = 2;
686 
687     /**
688      * A flag indicating whether any 5-way or DPAD navigation available.
689      * This will be set on a device with a mechanism to hide the navigation
690      * controls from the user, when that mechanism is closed.  One of:
691      * {@link #NAVIGATIONHIDDEN_NO}, {@link #NAVIGATIONHIDDEN_YES}.
692      */
693     public int navigationHidden;
694 
695     /** @hide **/
696     @IntDef(prefix = {"ORIENTATION_"}, value = {
697             ORIENTATION_UNDEFINED,
698             ORIENTATION_PORTRAIT,
699             ORIENTATION_LANDSCAPE,
700             ORIENTATION_SQUARE
701     })
702     @Retention(RetentionPolicy.SOURCE)
703     public @interface Orientation {
704     }
705 
706     /** Constant for {@link #orientation}: a value indicating that no value has been set. */
707     public static final int ORIENTATION_UNDEFINED = 0;
708     /** Constant for {@link #orientation}, value corresponding to the
709      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#OrientationQualifier">port</a>
710      * resource qualifier. */
711     public static final int ORIENTATION_PORTRAIT = 1;
712     /** Constant for {@link #orientation}, value corresponding to the
713      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#OrientationQualifier">land</a>
714      * resource qualifier. */
715     public static final int ORIENTATION_LANDSCAPE = 2;
716     /** @deprecated Not currently supported or used. */
717     @Deprecated public static final int ORIENTATION_SQUARE = 3;
718 
719     /**
720      * Overall orientation of the screen.  May be one of
721      * {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}.
722      */
723     @Orientation
724     public int orientation;
725 
726     /** Constant for {@link #uiMode}: bits that encode the mode type. */
727     public static final int UI_MODE_TYPE_MASK = 0x0f;
728     /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
729      * value indicating that no mode type has been set. */
730     public static final int UI_MODE_TYPE_UNDEFINED = 0x00;
731     /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
732      * value that corresponds to
733      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">no
734      * UI mode</a> resource qualifier specified. */
735     public static final int UI_MODE_TYPE_NORMAL = 0x01;
736     /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
737      * value that corresponds to the
738      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">desk</a>
739      * resource qualifier. */
740     public static final int UI_MODE_TYPE_DESK = 0x02;
741     /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
742      * value that corresponds to the
743      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">car</a>
744      * resource qualifier. */
745     public static final int UI_MODE_TYPE_CAR = 0x03;
746     /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
747      * value that corresponds to the
748      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">television</a>
749      * resource qualifier. */
750     public static final int UI_MODE_TYPE_TELEVISION = 0x04;
751     /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
752      * value that corresponds to the
753      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">appliance</a>
754      * resource qualifier. */
755     public static final int UI_MODE_TYPE_APPLIANCE = 0x05;
756     /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
757      * value that corresponds to the
758      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">watch</a>
759      * resource qualifier. */
760     public static final int UI_MODE_TYPE_WATCH = 0x06;
761     /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
762      * value that corresponds to the
763      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">vrheadset</a>
764      * resource qualifier. */
765     public static final int UI_MODE_TYPE_VR_HEADSET = 0x07;
766 
767     /** Constant for {@link #uiMode}: bits that encode the night mode. */
768     public static final int UI_MODE_NIGHT_MASK = 0x30;
769     /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK}
770      * value indicating that no mode type has been set. */
771     public static final int UI_MODE_NIGHT_UNDEFINED = 0x00;
772     /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK}
773      * value that corresponds to the
774      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NightQualifier">notnight</a>
775      * resource qualifier. */
776     public static final int UI_MODE_NIGHT_NO = 0x10;
777     /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK}
778      * value that corresponds to the
779      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NightQualifier">night</a>
780      * resource qualifier. */
781     public static final int UI_MODE_NIGHT_YES = 0x20;
782 
783     /**
784      * Bit mask of the ui mode.  Currently there are two fields:
785      * <p>The {@link #UI_MODE_TYPE_MASK} bits define the overall ui mode of the
786      * device. They may be one of {@link #UI_MODE_TYPE_UNDEFINED},
787      * {@link #UI_MODE_TYPE_NORMAL}, {@link #UI_MODE_TYPE_DESK},
788      * {@link #UI_MODE_TYPE_CAR}, {@link #UI_MODE_TYPE_TELEVISION},
789      * {@link #UI_MODE_TYPE_APPLIANCE}, {@link #UI_MODE_TYPE_WATCH},
790      * or {@link #UI_MODE_TYPE_VR_HEADSET}.
791      *
792      * <p>The {@link #UI_MODE_NIGHT_MASK} defines whether the screen
793      * is in a special mode. They may be one of {@link #UI_MODE_NIGHT_UNDEFINED},
794      * {@link #UI_MODE_NIGHT_NO} or {@link #UI_MODE_NIGHT_YES}.
795      */
796     public int uiMode;
797 
798     /**
799      * Default value for {@link #screenWidthDp} indicating that no width
800      * has been specified.
801      */
802     public static final int SCREEN_WIDTH_DP_UNDEFINED = 0;
803 
804     /**
805      * The width of the available screen space in dp units.
806      *
807      * <aside class="note"><b>Note:</b> If the app targets
808      * {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}
809      * or after, the width measurement reflects the window size without excluding insets.
810      * Otherwise, the measurement excludes window insets even when the app is displayed edge to edge
811      * using {@link android.view.Window#setDecorFitsSystemWindows(boolean)
812      * Window#setDecorFitsSystemWindows(boolean)}.</aside>
813      *
814      * Use {@link android.view.WindowMetrics#getBounds()} to always obtain the horizontal
815      * display area available to an app or embedded activity including the area
816      * occupied by window insets. A version of the API is also available for use on older platforms
817      * through {@link androidx.window.layout.WindowMetrics}.
818      *
819      * <p>Corresponds to the
820      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#AvailableWidthHeightQualifier">
821      * available width</a> resource qualifier. Defaults to
822      * {@link #SCREEN_WIDTH_DP_UNDEFINED} if no width is specified.
823      *
824      * <p>In multi-window mode, equals the width of the available display area
825      * of the app window, not the available display area of the device screen
826      * (for example, when apps are displayed side by side in split-screen mode
827      * in landscape orientation).
828      *
829      * <p>For embedded activities, equals the width of the individual
830      * activities, not the width of the app window or the device screen.
831      *
832      * <p>In multiple-screen scenarios, the width measurement can span screens.
833      * For example, if the app is spanning both screens of a dual-screen device
834      * (with the screens side by side), {@code screenWidthDp} represents the
835      * width of both screens excluding the area occupied by window insets. When
836      * the app is restricted to a single screen in a multiple-screen
837      * environment, {@code screenWidthDp} is the width of the screen on which
838      * the app is displayed excluding window insets.
839      *
840      * <p>If the app targets {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or after,
841      * it is the same as {@link android.view.WindowMetrics}, but is expressed rounded to the nearest
842      * dp rather than px.
843      *
844      * <p>Otherwise, differs from {@link android.view.WindowMetrics} by not including
845      * window insets in the width measurement and by expressing the measurement
846      * in dp rather than px. Use {@code screenWidthDp} to obtain the width of
847      * the display area available to an app or embedded activity excluding the
848      * area occupied by window insets.
849      */
850     public int screenWidthDp;
851 
852     /**
853      * Default value for {@link #screenHeightDp} indicating that no width
854      * has been specified.
855      */
856     public static final int SCREEN_HEIGHT_DP_UNDEFINED = 0;
857 
858     /**
859      * The height of the available screen space in dp units.
860      *
861      * <aside class="note"><b>Note:</b> If the app targets
862      * {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}
863      * or after, the height measurement reflects the window size without excluding insets.
864      * Otherwise, the measurement excludes window insets even when the app is displayed edge to edge
865      * using {@link android.view.Window#setDecorFitsSystemWindows(boolean)
866      * Window#setDecorFitsSystemWindows(boolean)}.</aside>
867      *
868      * Use {@link android.view.WindowMetrics#getBounds()} to always obtain the vertical
869      * display area available to an app or embedded activity including the area
870      * occupied by window insets. A version of the API is also available for use on older platforms
871      * through {@link androidx.window.layout.WindowMetrics}.
872      *
873      * <p>Corresponds to the
874      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#AvailableWidthHeightQualifier">
875      * available height</a> resource qualifier. Defaults to
876      * {@link #SCREEN_HEIGHT_DP_UNDEFINED} if no height is specified.
877      *
878      * <p>In multi-window mode, equals the height of the available display area
879      * of the app window, not the available display area of the device screen
880      * (for example, when apps are displayed one above another in split-screen
881      * mode in portrait orientation).
882      *
883      * <p>For embedded activities, equals the height of the individual
884      * activities, not the height of the app window or the device screen.
885      *
886      * <p>In multiple-screen scenarios, the height measurement can span screens.
887      * For example, if the app is spanning both screens of a dual-screen device
888      * rotated 90 degrees (one screen above the other), {@code screenHeightDp}
889      * represents the height of both screens excluding the area occupied by
890      * window insets. When the app is restricted to a single screen in a
891      * multiple-screen environment, {@code screenHeightDp} is the height of the
892      * screen on which the app is displayed excluding window insets.
893      *
894      * <p>If the app targets {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or after,
895      * it is the same as {@link android.view.WindowMetrics}, but is expressed rounded to the nearest
896      * dp rather than px.
897      *
898      * <p>Otherwise, differs from {@link android.view.WindowMetrics} by not including
899      * window insets in the height measurement and by expressing the measurement
900      * in dp rather than px. Use {@code screenHeightDp} to obtain the height of
901      * the display area available to an app or embedded activity excluding the
902      * area occupied by window insets.
903      */
904     public int screenHeightDp;
905 
906     /**
907      * Default value for {@link #smallestScreenWidthDp} indicating that no width
908      * has been specified.
909      */
910     public static final int SMALLEST_SCREEN_WIDTH_DP_UNDEFINED = 0;
911 
912     /**
913      * The smallest screen size an application will see in normal operation.
914      * Corresponds to the
915      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#SmallestScreenWidthQualifier">
916      * smallest width</a> resource qualifier. This is the smallest value of
917      * {@link #screenWidthDp} and {@link #screenHeightDp} in both portrait and
918      * landscape orientations. Defaults to
919      * {@link #SMALLEST_SCREEN_WIDTH_DP_UNDEFINED} if no width is specified.
920      */
921     public int smallestScreenWidthDp;
922 
923     /**
924      * Default value for {@link #densityDpi} indicating that no width
925      * has been specified.
926      */
927     public static final int DENSITY_DPI_UNDEFINED = 0;
928 
929     /**
930      * Value for {@link #densityDpi} for resources that scale to any density (vector drawables).
931      * {@hide}
932      */
933     public static final int DENSITY_DPI_ANY = 0xfffe;
934 
935     /**
936      * Value for {@link #densityDpi} for resources that are not meant to be scaled.
937      * {@hide}
938      */
939     public static final int DENSITY_DPI_NONE = 0xffff;
940 
941     /**
942      * The target screen density being rendered to,
943      * corresponding to
944      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#DensityQualifier">density</a>
945      * resource qualifier.  Set to
946      * {@link #DENSITY_DPI_UNDEFINED} if no density is specified.
947      */
948     public int densityDpi;
949 
950     /** @hide Hack to get this information from WM to app running in compat mode. */
951     public int compatScreenWidthDp;
952     /** @hide Hack to get this information from WM to app running in compat mode. */
953     public int compatScreenHeightDp;
954     /** @hide Hack to get this information from WM to app running in compat mode. */
955     public int compatSmallestScreenWidthDp;
956 
957     /**
958      * An undefined assetsSeq. This will not override an existing assetsSeq.
959      * @hide
960      */
961     public static final int ASSETS_SEQ_UNDEFINED = 0;
962 
963     /**
964      * Internal counter that allows us to piggyback off the configuration change mechanism to
965      * signal to apps that the the assets for an Application have changed. A difference in these
966      * between two Configurations will yield a diff flag of
967      * {@link ActivityInfo#CONFIG_ASSETS_PATHS}.
968      * @hide
969      */
970     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
971     @TestApi
972     public int assetsSeq;
973 
974     /**
975      * @hide Internal book-keeping.
976      */
977     @UnsupportedAppUsage
978     public int seq;
979 
980     /** @hide */
981     @IntDef(flag = true, prefix = { "NATIVE_CONFIG_" }, value = {
982             NATIVE_CONFIG_MCC,
983             NATIVE_CONFIG_MNC,
984             NATIVE_CONFIG_LOCALE,
985             NATIVE_CONFIG_TOUCHSCREEN,
986             NATIVE_CONFIG_KEYBOARD,
987             NATIVE_CONFIG_KEYBOARD_HIDDEN,
988             NATIVE_CONFIG_NAVIGATION,
989             NATIVE_CONFIG_ORIENTATION,
990             NATIVE_CONFIG_DENSITY,
991             NATIVE_CONFIG_SCREEN_SIZE,
992             NATIVE_CONFIG_VERSION,
993             NATIVE_CONFIG_SCREEN_LAYOUT,
994             NATIVE_CONFIG_UI_MODE,
995             NATIVE_CONFIG_SMALLEST_SCREEN_SIZE,
996             NATIVE_CONFIG_LAYOUTDIR,
997             NATIVE_CONFIG_COLOR_MODE,
998             NATIVE_CONFIG_GRAMMATICAL_GENDER,
999     })
1000     @Retention(RetentionPolicy.SOURCE)
1001     public @interface NativeConfig {}
1002 
1003     /** @hide Native-specific bit mask for MCC config; DO NOT USE UNLESS YOU ARE SURE. */
1004     public static final int NATIVE_CONFIG_MCC = 0x0001;
1005     /** @hide Native-specific bit mask for MNC config; DO NOT USE UNLESS YOU ARE SURE. */
1006     public static final int NATIVE_CONFIG_MNC = 0x0002;
1007     /** @hide Native-specific bit mask for LOCALE config; DO NOT USE UNLESS YOU ARE SURE. */
1008     public static final int NATIVE_CONFIG_LOCALE = 0x0004;
1009     /** @hide Native-specific bit mask for TOUCHSCREEN config; DO NOT USE UNLESS YOU ARE SURE. */
1010     public static final int NATIVE_CONFIG_TOUCHSCREEN = 0x0008;
1011     /** @hide Native-specific bit mask for KEYBOARD config; DO NOT USE UNLESS YOU ARE SURE. */
1012     public static final int NATIVE_CONFIG_KEYBOARD = 0x0010;
1013     /** @hide Native-specific bit mask for KEYBOARD_HIDDEN config; DO NOT USE UNLESS YOU
1014      * ARE SURE. */
1015     public static final int NATIVE_CONFIG_KEYBOARD_HIDDEN = 0x0020;
1016     /** @hide Native-specific bit mask for NAVIGATION config; DO NOT USE UNLESS YOU ARE SURE. */
1017     public static final int NATIVE_CONFIG_NAVIGATION = 0x0040;
1018     /** @hide Native-specific bit mask for ORIENTATION config; DO NOT USE UNLESS YOU ARE SURE. */
1019     public static final int NATIVE_CONFIG_ORIENTATION = 0x0080;
1020     /** @hide Native-specific bit mask for DENSITY config; DO NOT USE UNLESS YOU ARE SURE. */
1021     public static final int NATIVE_CONFIG_DENSITY = 0x0100;
1022     /** @hide Native-specific bit mask for SCREEN_SIZE config; DO NOT USE UNLESS YOU ARE SURE. */
1023     public static final int NATIVE_CONFIG_SCREEN_SIZE = 0x0200;
1024     /** @hide Native-specific bit mask for VERSION config; DO NOT USE UNLESS YOU ARE SURE. */
1025     public static final int NATIVE_CONFIG_VERSION = 0x0400;
1026     /** @hide Native-specific bit mask for SCREEN_LAYOUT config; DO NOT USE UNLESS YOU ARE SURE. */
1027     public static final int NATIVE_CONFIG_SCREEN_LAYOUT = 0x0800;
1028     /** @hide Native-specific bit mask for UI_MODE config; DO NOT USE UNLESS YOU ARE SURE. */
1029     public static final int NATIVE_CONFIG_UI_MODE = 0x1000;
1030     /** @hide Native-specific bit mask for SMALLEST_SCREEN_SIZE config; DO NOT USE UNLESS YOU
1031      * ARE SURE. */
1032     public static final int NATIVE_CONFIG_SMALLEST_SCREEN_SIZE = 0x2000;
1033     /** @hide Native-specific bit mask for LAYOUTDIR config ; DO NOT USE UNLESS YOU ARE SURE.*/
1034     public static final int NATIVE_CONFIG_LAYOUTDIR = 0x4000;
1035     /** @hide Native-specific bit mask for COLOR_MODE config ; DO NOT USE UNLESS YOU ARE SURE.*/
1036     public static final int NATIVE_CONFIG_COLOR_MODE = 0x10000;
1037     /** @hide Native-specific bit mask for GRAMMATICAL_GENDER config; DO NOT USE UNLESS YOU
1038      * ARE SURE.*/
1039     public static final int NATIVE_CONFIG_GRAMMATICAL_GENDER = 0x20000;
1040 
1041     /**
1042      * <p>Construct an invalid Configuration. This state is only suitable for constructing a
1043      * Configuration delta that will be applied to some valid Configuration object. In order to
1044      * create a valid standalone Configuration, you must call {@link #setToDefaults}. </p>
1045      *
1046      * <p>Example:</p>
1047      * <pre class="prettyprint">
1048      *     Configuration validConfig = new Configuration();
1049      *     validConfig.setToDefaults();
1050      *
1051      *     Configuration deltaOnlyConfig = new Configuration();
1052      *     deltaOnlyConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
1053      *
1054      *     validConfig.updateFrom(deltaOnlyConfig);
1055      * </pre>
1056      */
Configuration()1057     public Configuration() {
1058         unset();
1059     }
1060 
1061     /**
1062      * Makes a deep copy suitable for modification.
1063      */
Configuration(Configuration o)1064     public Configuration(Configuration o) {
1065         setTo(o);
1066     }
1067 
1068     /* This brings mLocaleList in sync with locale in case a user of the older API who doesn't know
1069      * about setLocales() has changed locale directly. */
fixUpLocaleList()1070     private void fixUpLocaleList() {
1071         if ((locale == null && !mLocaleList.isEmpty()) ||
1072                 (locale != null && !locale.equals(mLocaleList.get(0)))) {
1073             mLocaleList = locale == null ? LocaleList.getEmptyLocaleList() : new LocaleList(locale);
1074         }
1075     }
1076 
1077     /**
1078      * Sets the fields in this object to those in the given Configuration.
1079      *
1080      * @param o The Configuration object used to set the values of this Configuration's fields.
1081      */
setTo(Configuration o)1082     public void setTo(Configuration o) {
1083         fontScale = o.fontScale;
1084         mcc = o.mcc;
1085         mnc = o.mnc;
1086         if (o.locale == null) {
1087             locale = null;
1088         } else if (!o.locale.equals(locale)) {
1089             // Only clone a new Locale instance if we need to:  the clone() is
1090             // both CPU and GC intensive.
1091             locale = (Locale) o.locale.clone();
1092         }
1093         o.fixUpLocaleList();
1094         mLocaleList = o.mLocaleList;
1095         mGrammaticalGender = o.mGrammaticalGender;
1096         userSetLocale = o.userSetLocale;
1097         touchscreen = o.touchscreen;
1098         keyboard = o.keyboard;
1099         keyboardHidden = o.keyboardHidden;
1100         hardKeyboardHidden = o.hardKeyboardHidden;
1101         navigation = o.navigation;
1102         navigationHidden = o.navigationHidden;
1103         orientation = o.orientation;
1104         screenLayout = o.screenLayout;
1105         colorMode = o.colorMode;
1106         uiMode = o.uiMode;
1107         screenWidthDp = o.screenWidthDp;
1108         screenHeightDp = o.screenHeightDp;
1109         smallestScreenWidthDp = o.smallestScreenWidthDp;
1110         densityDpi = o.densityDpi;
1111         compatScreenWidthDp = o.compatScreenWidthDp;
1112         compatScreenHeightDp = o.compatScreenHeightDp;
1113         compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp;
1114         assetsSeq = o.assetsSeq;
1115         seq = o.seq;
1116         windowConfiguration.setTo(o.windowConfiguration);
1117         fontWeightAdjustment = o.fontWeightAdjustment;
1118     }
1119 
toString()1120     public String toString() {
1121         StringBuilder sb = new StringBuilder(128);
1122         sb.append("{");
1123         sb.append(fontScale);
1124         sb.append(" ");
1125         if (mcc != 0) {
1126             sb.append(mcc);
1127             sb.append("mcc");
1128         } else {
1129             sb.append("?mcc");
1130         }
1131         if (mnc != MNC_ZERO) {
1132             sb.append(mnc);
1133             sb.append("mnc");
1134         } else {
1135             sb.append("?mnc");
1136         }
1137         fixUpLocaleList();
1138         if (!mLocaleList.isEmpty()) {
1139             sb.append(" ");
1140             sb.append(mLocaleList);
1141         } else {
1142             sb.append(" ?localeList");
1143         }
1144         if (mGrammaticalGender > 0) {
1145             switch (mGrammaticalGender) {
1146                 case GRAMMATICAL_GENDER_NEUTRAL: sb.append(" neuter"); break;
1147                 case GRAMMATICAL_GENDER_FEMININE: sb.append(" feminine"); break;
1148                 case GRAMMATICAL_GENDER_MASCULINE: sb.append(" masculine"); break;
1149                 default: sb.append(" ?grgend"); break;
1150             }
1151         }
1152         int layoutDir = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK);
1153         switch (layoutDir) {
1154             case SCREENLAYOUT_LAYOUTDIR_UNDEFINED: sb.append(" ?layoutDir"); break;
1155             case SCREENLAYOUT_LAYOUTDIR_LTR: sb.append(" ldltr"); break;
1156             case SCREENLAYOUT_LAYOUTDIR_RTL: sb.append(" ldrtl"); break;
1157             default: sb.append(" layoutDir=");
1158                 sb.append(layoutDir >> SCREENLAYOUT_LAYOUTDIR_SHIFT); break;
1159         }
1160         if (smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
1161             sb.append(" sw"); sb.append(smallestScreenWidthDp); sb.append("dp");
1162         } else {
1163             sb.append(" ?swdp");
1164         }
1165         if (screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) {
1166             sb.append(" w"); sb.append(screenWidthDp); sb.append("dp");
1167         } else {
1168             sb.append(" ?wdp");
1169         }
1170         if (screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) {
1171             sb.append(" h"); sb.append(screenHeightDp); sb.append("dp");
1172         } else {
1173             sb.append(" ?hdp");
1174         }
1175         if (densityDpi != DENSITY_DPI_UNDEFINED) {
1176             sb.append(" "); sb.append(densityDpi); sb.append("dpi");
1177         } else {
1178             sb.append(" ?density");
1179         }
1180         switch ((screenLayout&SCREENLAYOUT_SIZE_MASK)) {
1181             case SCREENLAYOUT_SIZE_UNDEFINED: sb.append(" ?lsize"); break;
1182             case SCREENLAYOUT_SIZE_SMALL: sb.append(" smll"); break;
1183             case SCREENLAYOUT_SIZE_NORMAL: sb.append(" nrml"); break;
1184             case SCREENLAYOUT_SIZE_LARGE: sb.append(" lrg"); break;
1185             case SCREENLAYOUT_SIZE_XLARGE: sb.append(" xlrg"); break;
1186             default: sb.append(" layoutSize=");
1187                     sb.append(screenLayout&SCREENLAYOUT_SIZE_MASK); break;
1188         }
1189         switch ((screenLayout&SCREENLAYOUT_LONG_MASK)) {
1190             case SCREENLAYOUT_LONG_UNDEFINED: sb.append(" ?long"); break;
1191             case SCREENLAYOUT_LONG_NO: /* not-long is not interesting to print */ break;
1192             case SCREENLAYOUT_LONG_YES: sb.append(" long"); break;
1193             default: sb.append(" layoutLong=");
1194                     sb.append(screenLayout&SCREENLAYOUT_LONG_MASK); break;
1195         }
1196         switch ((colorMode &COLOR_MODE_HDR_MASK)) {
1197             case COLOR_MODE_HDR_UNDEFINED: sb.append(" ?ldr"); break; // most likely not HDR
1198             case COLOR_MODE_HDR_NO: /* ldr is not interesting to print */ break;
1199             case COLOR_MODE_HDR_YES: sb.append(" hdr"); break;
1200             default: sb.append(" dynamicRange=");
1201                 sb.append(colorMode &COLOR_MODE_HDR_MASK); break;
1202         }
1203         switch ((colorMode &COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) {
1204             case COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED: sb.append(" ?wideColorGamut"); break;
1205             case COLOR_MODE_WIDE_COLOR_GAMUT_NO: /* not wide is not interesting to print */ break;
1206             case COLOR_MODE_WIDE_COLOR_GAMUT_YES: sb.append(" widecg"); break;
1207             default: sb.append(" wideColorGamut=");
1208                 sb.append(colorMode &COLOR_MODE_WIDE_COLOR_GAMUT_MASK); break;
1209         }
1210         switch (orientation) {
1211             case ORIENTATION_UNDEFINED: sb.append(" ?orien"); break;
1212             case ORIENTATION_LANDSCAPE: sb.append(" land"); break;
1213             case ORIENTATION_PORTRAIT: sb.append(" port"); break;
1214             default: sb.append(" orien="); sb.append(orientation); break;
1215         }
1216         switch ((uiMode&UI_MODE_TYPE_MASK)) {
1217             case UI_MODE_TYPE_UNDEFINED: sb.append(" ?uimode"); break;
1218             case UI_MODE_TYPE_NORMAL: /* normal is not interesting to print */ break;
1219             case UI_MODE_TYPE_DESK: sb.append(" desk"); break;
1220             case UI_MODE_TYPE_CAR: sb.append(" car"); break;
1221             case UI_MODE_TYPE_TELEVISION: sb.append(" television"); break;
1222             case UI_MODE_TYPE_APPLIANCE: sb.append(" appliance"); break;
1223             case UI_MODE_TYPE_WATCH: sb.append(" watch"); break;
1224             case UI_MODE_TYPE_VR_HEADSET: sb.append(" vrheadset"); break;
1225             default: sb.append(" uimode="); sb.append(uiMode&UI_MODE_TYPE_MASK); break;
1226         }
1227         switch ((uiMode&UI_MODE_NIGHT_MASK)) {
1228             case UI_MODE_NIGHT_UNDEFINED: sb.append(" ?night"); break;
1229             case UI_MODE_NIGHT_NO: /* not-night is not interesting to print */ break;
1230             case UI_MODE_NIGHT_YES: sb.append(" night"); break;
1231             default: sb.append(" night="); sb.append(uiMode&UI_MODE_NIGHT_MASK); break;
1232         }
1233         switch (touchscreen) {
1234             case TOUCHSCREEN_UNDEFINED: sb.append(" ?touch"); break;
1235             case TOUCHSCREEN_NOTOUCH: sb.append(" -touch"); break;
1236             case TOUCHSCREEN_STYLUS: sb.append(" stylus"); break;
1237             case TOUCHSCREEN_FINGER: sb.append(" finger"); break;
1238             default: sb.append(" touch="); sb.append(touchscreen); break;
1239         }
1240         switch (keyboard) {
1241             case KEYBOARD_UNDEFINED: sb.append(" ?keyb"); break;
1242             case KEYBOARD_NOKEYS: sb.append(" -keyb"); break;
1243             case KEYBOARD_QWERTY: sb.append(" qwerty"); break;
1244             case KEYBOARD_12KEY: sb.append(" 12key"); break;
1245             default: sb.append(" keys="); sb.append(keyboard); break;
1246         }
1247         switch (keyboardHidden) {
1248             case KEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break;
1249             case KEYBOARDHIDDEN_NO: sb.append("/v"); break;
1250             case KEYBOARDHIDDEN_YES: sb.append("/h"); break;
1251             case KEYBOARDHIDDEN_SOFT: sb.append("/s"); break;
1252             default: sb.append("/"); sb.append(keyboardHidden); break;
1253         }
1254         switch (hardKeyboardHidden) {
1255             case HARDKEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break;
1256             case HARDKEYBOARDHIDDEN_NO: sb.append("/v"); break;
1257             case HARDKEYBOARDHIDDEN_YES: sb.append("/h"); break;
1258             default: sb.append("/"); sb.append(hardKeyboardHidden); break;
1259         }
1260         switch (navigation) {
1261             case NAVIGATION_UNDEFINED: sb.append(" ?nav"); break;
1262             case NAVIGATION_NONAV: sb.append(" -nav"); break;
1263             case NAVIGATION_DPAD: sb.append(" dpad"); break;
1264             case NAVIGATION_TRACKBALL: sb.append(" tball"); break;
1265             case NAVIGATION_WHEEL: sb.append(" wheel"); break;
1266             default: sb.append(" nav="); sb.append(navigation); break;
1267         }
1268         switch (navigationHidden) {
1269             case NAVIGATIONHIDDEN_UNDEFINED: sb.append("/?"); break;
1270             case NAVIGATIONHIDDEN_NO: sb.append("/v"); break;
1271             case NAVIGATIONHIDDEN_YES: sb.append("/h"); break;
1272             default: sb.append("/"); sb.append(navigationHidden); break;
1273         }
1274         sb.append(" winConfig="); sb.append(windowConfiguration);
1275         if (assetsSeq != 0) {
1276             sb.append(" as.").append(assetsSeq);
1277         }
1278         if (seq != 0) {
1279             sb.append(" s.").append(seq);
1280         }
1281         if (fontWeightAdjustment != FONT_WEIGHT_ADJUSTMENT_UNDEFINED) {
1282             sb.append(" fontWeightAdjustment=");
1283             sb.append(fontWeightAdjustment);
1284         } else {
1285             sb.append(" ?fontWeightAdjustment");
1286         }
1287         sb.append('}');
1288         return sb.toString();
1289     }
1290 
1291     /**
1292      * Write to a protocol buffer output stream.
1293      * Protocol buffer message definition at {@link android.content.ConfigurationProto}
1294      * Has the option to ignore fields that don't need to be persisted to disk.
1295      *
1296      * @param protoOutputStream Stream to write the Configuration object to.
1297      * @param fieldId           Field Id of the Configuration as defined in the parent message
1298      * @param persisted         Note if this proto will be persisted to disk
1299      * @param critical          If true, reduce amount of data written.
1300      * @hide
1301      */
dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean persisted, boolean critical)1302     public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean persisted,
1303             boolean critical) {
1304         final long token = protoOutputStream.start(fieldId);
1305         if (!critical) {
1306             protoOutputStream.write(FONT_SCALE, fontScale);
1307             protoOutputStream.write(MCC, mcc);
1308             protoOutputStream.write(MNC, mnc);
1309             if (mLocaleList != null) {
1310                 protoOutputStream.write(LOCALE_LIST, mLocaleList.toLanguageTags());
1311             }
1312             protoOutputStream.write(SCREEN_LAYOUT, screenLayout);
1313             protoOutputStream.write(COLOR_MODE, colorMode);
1314             protoOutputStream.write(TOUCHSCREEN, touchscreen);
1315             protoOutputStream.write(KEYBOARD, keyboard);
1316             protoOutputStream.write(KEYBOARD_HIDDEN, keyboardHidden);
1317             protoOutputStream.write(HARD_KEYBOARD_HIDDEN, hardKeyboardHidden);
1318             protoOutputStream.write(NAVIGATION, navigation);
1319             protoOutputStream.write(NAVIGATION_HIDDEN, navigationHidden);
1320             protoOutputStream.write(UI_MODE, uiMode);
1321             protoOutputStream.write(SMALLEST_SCREEN_WIDTH_DP, smallestScreenWidthDp);
1322             protoOutputStream.write(DENSITY_DPI, densityDpi);
1323             // For persistence, we do not care about window configuration
1324             if (!persisted && windowConfiguration != null) {
1325                 windowConfiguration.dumpDebug(protoOutputStream, WINDOW_CONFIGURATION);
1326             }
1327             protoOutputStream.write(FONT_WEIGHT_ADJUSTMENT, fontWeightAdjustment);
1328         }
1329         protoOutputStream.write(ORIENTATION, orientation);
1330         protoOutputStream.write(SCREEN_WIDTH_DP, screenWidthDp);
1331         protoOutputStream.write(SCREEN_HEIGHT_DP, screenHeightDp);
1332         protoOutputStream.write(GRAMMATICAL_GENDER, mGrammaticalGender);
1333         protoOutputStream.end(token);
1334     }
1335 
1336     /**
1337      * Write to a protocol buffer output stream.
1338      * Protocol buffer message definition at {@link android.content.ConfigurationProto}
1339      *
1340      * @param protoOutputStream Stream to write the Configuration object to.
1341      * @param fieldId           Field Id of the Configuration as defined in the parent message
1342      * @hide
1343      */
dumpDebug(ProtoOutputStream protoOutputStream, long fieldId)1344     public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId) {
1345         dumpDebug(protoOutputStream, fieldId, false /* persisted */, false /* critical */);
1346     }
1347 
1348     /**
1349      * Write to a protocol buffer output stream.
1350      * Protocol buffer message definition at {@link android.content.ConfigurationProto}
1351      *
1352      * @param protoOutputStream Stream to write the Configuration object to.
1353      * @param fieldId           Field Id of the Configuration as defined in the parent message
1354      * @param critical          If true, reduce amount of data written.
1355      * @hide
1356      */
dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean critical)1357     public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean critical) {
1358         dumpDebug(protoOutputStream, fieldId, false /* persisted */, critical);
1359     }
1360 
1361     /**
1362      * Read from a protocol buffer output stream.
1363      * Protocol buffer message definition at {@link android.content.ConfigurationProto}
1364      *
1365      * @param protoInputStream Stream to read the Configuration object from.
1366      * @param fieldId          Field Id of the Configuration as defined in the parent message
1367      * @hide
1368      */
readFromProto(ProtoInputStream protoInputStream, long fieldId)1369     public void readFromProto(ProtoInputStream protoInputStream, long fieldId) throws IOException {
1370         final long token = protoInputStream.start(fieldId);
1371         final List<Locale> list = new ArrayList();
1372         try {
1373             while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
1374                 switch (protoInputStream.getFieldNumber()) {
1375                     case (int) FONT_SCALE:
1376                         fontScale = protoInputStream.readFloat(FONT_SCALE);
1377                         break;
1378                     case (int) MCC:
1379                         mcc = protoInputStream.readInt(MCC);
1380                         break;
1381                     case (int) MNC:
1382                         mnc = protoInputStream.readInt(MNC);
1383                         break;
1384                     case (int) LOCALES:
1385                         // Parse the Locale here to handle all the repeated Locales
1386                         // The LocaleList will be created when the message is completed
1387                         final long localeToken = protoInputStream.start(LOCALES);
1388                         String language = "";
1389                         String country = "";
1390                         String variant = "";
1391                         String script = "";
1392                         try {
1393                             while (protoInputStream.nextField()
1394                                     != ProtoInputStream.NO_MORE_FIELDS) {
1395                                 switch (protoInputStream.getFieldNumber()) {
1396                                     case (int) LocaleProto.LANGUAGE:
1397                                         language = protoInputStream.readString(
1398                                                 LocaleProto.LANGUAGE);
1399                                         break;
1400                                     case (int) LocaleProto.COUNTRY:
1401                                         country = protoInputStream.readString(LocaleProto.COUNTRY);
1402                                         break;
1403                                     case (int) LocaleProto.VARIANT:
1404                                         variant = protoInputStream.readString(LocaleProto.VARIANT);
1405                                         break;
1406                                     case (int) LocaleProto.SCRIPT:
1407                                         script = protoInputStream.readString(LocaleProto.SCRIPT);
1408                                         break;
1409                                 }
1410                             }
1411                         } catch (WireTypeMismatchException wtme) {
1412                             // rethrow for caller deal with
1413                             throw wtme;
1414                         } finally {
1415                             protoInputStream.end(localeToken);
1416                             try {
1417                                 final Locale locale = new Locale.Builder()
1418                                                         .setLanguage(language)
1419                                                         .setRegion(country)
1420                                                         .setVariant(variant)
1421                                                         .setScript(script)
1422                                                         .build();
1423                                 // Log a WTF here if a repeated locale is found to avoid throwing an
1424                                 // exception in system server when LocaleList is created below
1425                                 final int inListIndex = list.indexOf(locale);
1426                                 if (inListIndex != -1) {
1427                                     Slog.wtf(TAG, "Repeated locale (" + list.get(inListIndex) + ")"
1428                                             + " found when trying to add: " + locale.toString());
1429                                 } else {
1430                                     list.add(locale);
1431                                 }
1432                             } catch (IllformedLocaleException e) {
1433                                 Slog.e(TAG, "readFromProto error building locale with: "
1434                                         + "language-" + language + ";country-" + country
1435                                         + ";variant-" + variant + ";script-" + script);
1436                             }
1437                         }
1438                         break;
1439                     case (int) SCREEN_LAYOUT:
1440                         screenLayout = protoInputStream.readInt(SCREEN_LAYOUT);
1441                         break;
1442                     case (int) COLOR_MODE:
1443                         colorMode = protoInputStream.readInt(COLOR_MODE);
1444                         break;
1445                     case (int) TOUCHSCREEN:
1446                         touchscreen = protoInputStream.readInt(TOUCHSCREEN);
1447                         break;
1448                     case (int) KEYBOARD:
1449                         keyboard = protoInputStream.readInt(KEYBOARD);
1450                         break;
1451                     case (int) KEYBOARD_HIDDEN:
1452                         keyboardHidden = protoInputStream.readInt(KEYBOARD_HIDDEN);
1453                         break;
1454                     case (int) HARD_KEYBOARD_HIDDEN:
1455                         hardKeyboardHidden = protoInputStream.readInt(HARD_KEYBOARD_HIDDEN);
1456                         break;
1457                     case (int) NAVIGATION:
1458                         navigation = protoInputStream.readInt(NAVIGATION);
1459                         break;
1460                     case (int) NAVIGATION_HIDDEN:
1461                         navigationHidden = protoInputStream.readInt(NAVIGATION_HIDDEN);
1462                         break;
1463                     case (int) ORIENTATION:
1464                         orientation = protoInputStream.readInt(ORIENTATION);
1465                         break;
1466                     case (int) UI_MODE:
1467                         uiMode = protoInputStream.readInt(UI_MODE);
1468                         break;
1469                     case (int) SCREEN_WIDTH_DP:
1470                         screenWidthDp = protoInputStream.readInt(SCREEN_WIDTH_DP);
1471                         break;
1472                     case (int) SCREEN_HEIGHT_DP:
1473                         screenHeightDp = protoInputStream.readInt(SCREEN_HEIGHT_DP);
1474                         break;
1475                     case (int) SMALLEST_SCREEN_WIDTH_DP:
1476                         smallestScreenWidthDp = protoInputStream.readInt(SMALLEST_SCREEN_WIDTH_DP);
1477                         break;
1478                     case (int) DENSITY_DPI:
1479                         densityDpi = protoInputStream.readInt(DENSITY_DPI);
1480                         break;
1481                     case (int) WINDOW_CONFIGURATION:
1482                         windowConfiguration.readFromProto(protoInputStream, WINDOW_CONFIGURATION);
1483                         break;
1484                     case (int) LOCALE_LIST:
1485                         try {
1486                             setLocales(LocaleList.forLanguageTags(protoInputStream.readString(
1487                                     LOCALE_LIST)));
1488                         } catch (Exception e) {
1489                             Slog.e(TAG, "error parsing locale list in configuration.", e);
1490                         }
1491                         break;
1492                     case (int) FONT_WEIGHT_ADJUSTMENT:
1493                         fontWeightAdjustment = protoInputStream.readInt(FONT_WEIGHT_ADJUSTMENT);
1494                         break;
1495                     case (int) GRAMMATICAL_GENDER:
1496                         mGrammaticalGender = protoInputStream.readInt(GRAMMATICAL_GENDER);
1497                         break;
1498                 }
1499             }
1500         } finally {
1501             // Let caller handle any exceptions
1502             if (list.size() > 0) {
1503                 //Create the LocaleList from the collected Locales
1504                 setLocales(new LocaleList(list.toArray(new Locale[list.size()])));
1505             }
1506             protoInputStream.end(token);
1507         }
1508     }
1509 
1510     /**
1511      * Write full {@link android.content.ResourcesConfigurationProto} to protocol buffer output
1512      * stream.
1513      *
1514      * @param protoOutputStream Stream to write the Configuration object to.
1515      * @param fieldId           Field Id of the Configuration as defined in the parent message
1516      * @param metrics           Current display information
1517      * @hide
1518      */
writeResConfigToProto(ProtoOutputStream protoOutputStream, long fieldId, DisplayMetrics metrics)1519     public void writeResConfigToProto(ProtoOutputStream protoOutputStream, long fieldId,
1520             DisplayMetrics metrics) {
1521         final int width, height;
1522         if (metrics.widthPixels >= metrics.heightPixels) {
1523             width = metrics.widthPixels;
1524             height = metrics.heightPixels;
1525         } else {
1526             //noinspection SuspiciousNameCombination
1527             width = metrics.heightPixels;
1528             //noinspection SuspiciousNameCombination
1529             height = metrics.widthPixels;
1530         }
1531 
1532         final long token = protoOutputStream.start(fieldId);
1533         dumpDebug(protoOutputStream, CONFIGURATION);
1534         protoOutputStream.write(SDK_VERSION, Build.VERSION.RESOURCES_SDK_INT);
1535         protoOutputStream.write(SCREEN_WIDTH_PX, width);
1536         protoOutputStream.write(SCREEN_HEIGHT_PX, height);
1537         protoOutputStream.end(token);
1538     }
1539 
1540     /**
1541      * Convert the UI mode to a human readable format.
1542      * @hide
1543      */
uiModeToString(int uiMode)1544     public static String uiModeToString(int uiMode) {
1545         switch (uiMode) {
1546             case UI_MODE_TYPE_UNDEFINED:
1547                 return "UI_MODE_TYPE_UNDEFINED";
1548             case UI_MODE_TYPE_NORMAL:
1549                 return "UI_MODE_TYPE_NORMAL";
1550             case UI_MODE_TYPE_DESK:
1551                 return "UI_MODE_TYPE_DESK";
1552             case UI_MODE_TYPE_CAR:
1553                 return "UI_MODE_TYPE_CAR";
1554             case UI_MODE_TYPE_TELEVISION:
1555                 return "UI_MODE_TYPE_TELEVISION";
1556             case UI_MODE_TYPE_APPLIANCE:
1557                 return "UI_MODE_TYPE_APPLIANCE";
1558             case UI_MODE_TYPE_WATCH:
1559                 return "UI_MODE_TYPE_WATCH";
1560             case UI_MODE_TYPE_VR_HEADSET:
1561                 return "UI_MODE_TYPE_VR_HEADSET";
1562             default:
1563                 return Integer.toString(uiMode);
1564         }
1565     }
1566 
1567     /**
1568      * Set this object to the system defaults.
1569      */
setToDefaults()1570     public void setToDefaults() {
1571         fontScale = 1;
1572         mcc = mnc = 0;
1573         mLocaleList = LocaleList.getEmptyLocaleList();
1574         locale = null;
1575         userSetLocale = false;
1576         touchscreen = TOUCHSCREEN_UNDEFINED;
1577         keyboard = KEYBOARD_UNDEFINED;
1578         keyboardHidden = KEYBOARDHIDDEN_UNDEFINED;
1579         hardKeyboardHidden = HARDKEYBOARDHIDDEN_UNDEFINED;
1580         navigation = NAVIGATION_UNDEFINED;
1581         navigationHidden = NAVIGATIONHIDDEN_UNDEFINED;
1582         orientation = ORIENTATION_UNDEFINED;
1583         screenLayout = SCREENLAYOUT_UNDEFINED;
1584         colorMode = COLOR_MODE_UNDEFINED;
1585         uiMode = UI_MODE_TYPE_UNDEFINED;
1586         screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
1587         screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
1588         smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
1589         densityDpi = DENSITY_DPI_UNDEFINED;
1590         assetsSeq = ASSETS_SEQ_UNDEFINED;
1591         seq = 0;
1592         windowConfiguration.setToDefaults();
1593         fontWeightAdjustment = FONT_WEIGHT_ADJUSTMENT_UNDEFINED;
1594         mGrammaticalGender = GRAMMATICAL_GENDER_UNDEFINED;
1595     }
1596 
1597     /**
1598      * Set this object to completely undefined.
1599      * @hide
1600      */
unset()1601     public void unset() {
1602         setToDefaults();
1603         fontScale = 0;
1604     }
1605 
1606     /** {@hide} */
1607     @UnsupportedAppUsage
makeDefault()1608     @Deprecated public void makeDefault() {
1609         setToDefaults();
1610     }
1611 
1612     /**
1613      * Copies the fields from delta into this Configuration object, keeping
1614      * track of which ones have changed. Any undefined fields in {@code delta}
1615      * are ignored and not copied in to the current Configuration.
1616      *
1617      * @return a bit mask of the changed fields, as per {@link #diff}
1618      */
updateFrom(@onNull Configuration delta)1619     public @Config int updateFrom(@NonNull Configuration delta) {
1620         int changed = 0;
1621         if (delta.fontScale > 0 && fontScale != delta.fontScale) {
1622             changed |= ActivityInfo.CONFIG_FONT_SCALE;
1623             fontScale = delta.fontScale;
1624         }
1625         if (delta.mcc != 0 && mcc != delta.mcc) {
1626             changed |= ActivityInfo.CONFIG_MCC;
1627             mcc = delta.mcc;
1628         }
1629         if (delta.mnc != 0 && mnc != delta.mnc) {
1630             changed |= ActivityInfo.CONFIG_MNC;
1631             mnc = delta.mnc;
1632         }
1633         fixUpLocaleList();
1634         delta.fixUpLocaleList();
1635         if (!delta.mLocaleList.isEmpty() && !mLocaleList.equals(delta.mLocaleList)) {
1636             changed |= ActivityInfo.CONFIG_LOCALE;
1637             mLocaleList = delta.mLocaleList;
1638             // delta.locale can't be null, since delta.mLocaleList is not empty.
1639             if (!delta.locale.equals(locale)) {
1640                 locale = (Locale) delta.locale.clone();
1641                 // If locale has changed, then layout direction is also changed ...
1642                 changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
1643                 // ... and we need to update the layout direction (represented by the first
1644                 // 2 most significant bits in screenLayout).
1645                 setLayoutDirection(locale);
1646             }
1647         }
1648         final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
1649         if (deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED &&
1650                 deltaScreenLayoutDir != (screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) {
1651             screenLayout = (screenLayout & ~SCREENLAYOUT_LAYOUTDIR_MASK) | deltaScreenLayoutDir;
1652             changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
1653         }
1654         if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
1655         {
1656             changed |= ActivityInfo.CONFIG_LOCALE;
1657             userSetLocale = true;
1658         }
1659         if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
1660                 && touchscreen != delta.touchscreen) {
1661             changed |= ActivityInfo.CONFIG_TOUCHSCREEN;
1662             touchscreen = delta.touchscreen;
1663         }
1664         if (delta.keyboard != KEYBOARD_UNDEFINED
1665                 && keyboard != delta.keyboard) {
1666             changed |= ActivityInfo.CONFIG_KEYBOARD;
1667             keyboard = delta.keyboard;
1668         }
1669         if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED
1670                 && keyboardHidden != delta.keyboardHidden) {
1671             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
1672             keyboardHidden = delta.keyboardHidden;
1673         }
1674         if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED
1675                 && hardKeyboardHidden != delta.hardKeyboardHidden) {
1676             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
1677             hardKeyboardHidden = delta.hardKeyboardHidden;
1678         }
1679         if (delta.navigation != NAVIGATION_UNDEFINED
1680                 && navigation != delta.navigation) {
1681             changed |= ActivityInfo.CONFIG_NAVIGATION;
1682             navigation = delta.navigation;
1683         }
1684         if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED
1685                 && navigationHidden != delta.navigationHidden) {
1686             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
1687             navigationHidden = delta.navigationHidden;
1688         }
1689         if (delta.orientation != ORIENTATION_UNDEFINED
1690                 && orientation != delta.orientation) {
1691             changed |= ActivityInfo.CONFIG_ORIENTATION;
1692             orientation = delta.orientation;
1693         }
1694         if (((delta.screenLayout & SCREENLAYOUT_SIZE_MASK) != SCREENLAYOUT_SIZE_UNDEFINED)
1695                 && (delta.screenLayout & SCREENLAYOUT_SIZE_MASK)
1696                 != (screenLayout & SCREENLAYOUT_SIZE_MASK)) {
1697             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
1698             screenLayout = (screenLayout & ~SCREENLAYOUT_SIZE_MASK)
1699                     | (delta.screenLayout & SCREENLAYOUT_SIZE_MASK);
1700         }
1701         if (((delta.screenLayout & SCREENLAYOUT_LONG_MASK) != SCREENLAYOUT_LONG_UNDEFINED)
1702                 && (delta.screenLayout & SCREENLAYOUT_LONG_MASK)
1703                 != (screenLayout & SCREENLAYOUT_LONG_MASK)) {
1704             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
1705             screenLayout = (screenLayout & ~SCREENLAYOUT_LONG_MASK)
1706                     | (delta.screenLayout & SCREENLAYOUT_LONG_MASK);
1707         }
1708         if (((delta.screenLayout & SCREENLAYOUT_ROUND_MASK) != SCREENLAYOUT_ROUND_UNDEFINED)
1709                 && (delta.screenLayout & SCREENLAYOUT_ROUND_MASK)
1710                 != (screenLayout & SCREENLAYOUT_ROUND_MASK)) {
1711             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
1712             screenLayout = (screenLayout & ~SCREENLAYOUT_ROUND_MASK)
1713                     | (delta.screenLayout & SCREENLAYOUT_ROUND_MASK);
1714         }
1715         if ((delta.screenLayout & SCREENLAYOUT_COMPAT_NEEDED)
1716                 != (screenLayout & SCREENLAYOUT_COMPAT_NEEDED)
1717                 && delta.screenLayout != 0) {
1718             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
1719             screenLayout = (screenLayout & ~SCREENLAYOUT_COMPAT_NEEDED)
1720                 | (delta.screenLayout & SCREENLAYOUT_COMPAT_NEEDED);
1721         }
1722 
1723         if (((delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) !=
1724                      COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED)
1725                 && (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)
1726                 != (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) {
1727             changed |= ActivityInfo.CONFIG_COLOR_MODE;
1728             colorMode = (colorMode & ~COLOR_MODE_WIDE_COLOR_GAMUT_MASK)
1729                     | (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK);
1730         }
1731 
1732         if (((delta.colorMode & COLOR_MODE_HDR_MASK) != COLOR_MODE_HDR_UNDEFINED)
1733                 && (delta.colorMode & COLOR_MODE_HDR_MASK)
1734                 != (colorMode & COLOR_MODE_HDR_MASK)) {
1735             changed |= ActivityInfo.CONFIG_COLOR_MODE;
1736             colorMode = (colorMode & ~COLOR_MODE_HDR_MASK)
1737                     | (delta.colorMode & COLOR_MODE_HDR_MASK);
1738         }
1739 
1740         if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED)
1741                 && uiMode != delta.uiMode) {
1742             changed |= ActivityInfo.CONFIG_UI_MODE;
1743             if ((delta.uiMode&UI_MODE_TYPE_MASK) != UI_MODE_TYPE_UNDEFINED) {
1744                 uiMode = (uiMode&~UI_MODE_TYPE_MASK)
1745                         | (delta.uiMode&UI_MODE_TYPE_MASK);
1746             }
1747             if ((delta.uiMode&UI_MODE_NIGHT_MASK) != UI_MODE_NIGHT_UNDEFINED) {
1748                 uiMode = (uiMode&~UI_MODE_NIGHT_MASK)
1749                         | (delta.uiMode&UI_MODE_NIGHT_MASK);
1750             }
1751         }
1752         if (delta.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED
1753                 && screenWidthDp != delta.screenWidthDp) {
1754             changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
1755             screenWidthDp = delta.screenWidthDp;
1756         }
1757         if (delta.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED
1758                 && screenHeightDp != delta.screenHeightDp) {
1759             changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
1760             screenHeightDp = delta.screenHeightDp;
1761         }
1762         if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
1763                 && smallestScreenWidthDp != delta.smallestScreenWidthDp) {
1764             changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
1765             smallestScreenWidthDp = delta.smallestScreenWidthDp;
1766         }
1767         if (delta.densityDpi != DENSITY_DPI_UNDEFINED &&
1768                 densityDpi != delta.densityDpi) {
1769             changed |= ActivityInfo.CONFIG_DENSITY;
1770             densityDpi = delta.densityDpi;
1771         }
1772         if (delta.compatScreenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) {
1773             compatScreenWidthDp = delta.compatScreenWidthDp;
1774         }
1775         if (delta.compatScreenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) {
1776             compatScreenHeightDp = delta.compatScreenHeightDp;
1777         }
1778         if (delta.compatSmallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
1779             compatSmallestScreenWidthDp = delta.compatSmallestScreenWidthDp;
1780         }
1781         if (delta.assetsSeq != ASSETS_SEQ_UNDEFINED && delta.assetsSeq != assetsSeq) {
1782             changed |= ActivityInfo.CONFIG_ASSETS_PATHS;
1783             assetsSeq = delta.assetsSeq;
1784         }
1785         if (delta.seq != 0) {
1786             seq = delta.seq;
1787         }
1788         if (windowConfiguration.updateFrom(delta.windowConfiguration) != 0) {
1789             changed |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
1790         }
1791 
1792         if (delta.fontWeightAdjustment != FONT_WEIGHT_ADJUSTMENT_UNDEFINED
1793                 && delta.fontWeightAdjustment != fontWeightAdjustment) {
1794             changed |= ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT;
1795             fontWeightAdjustment = delta.fontWeightAdjustment;
1796         }
1797         if (delta.mGrammaticalGender != GRAMMATICAL_GENDER_UNDEFINED
1798                 && delta.mGrammaticalGender != mGrammaticalGender) {
1799             changed |= ActivityInfo.CONFIG_GRAMMATICAL_GENDER;
1800             mGrammaticalGender = delta.mGrammaticalGender;
1801         }
1802 
1803         return changed;
1804     }
1805 
1806     /**
1807      * Copies the fields specified by mask from delta into this Configuration object. This will
1808      * copy anything allowed by the mask (including undefined values).
1809      * @hide
1810      */
setTo(@onNull Configuration delta, @Config int mask, @WindowConfiguration.WindowConfig int windowMask)1811     public void setTo(@NonNull Configuration delta, @Config int mask,
1812             @WindowConfiguration.WindowConfig int windowMask) {
1813         if ((mask & ActivityInfo.CONFIG_FONT_SCALE) != 0) {
1814             fontScale = delta.fontScale;
1815         }
1816         if ((mask & ActivityInfo.CONFIG_MCC) != 0) {
1817             mcc = delta.mcc;
1818         }
1819         if ((mask & ActivityInfo.CONFIG_MNC) != 0) {
1820             mnc = delta.mnc;
1821         }
1822         if ((mask & ActivityInfo.CONFIG_LOCALE) != 0) {
1823             mLocaleList = delta.mLocaleList;
1824             if (!mLocaleList.isEmpty()) {
1825                 if (!delta.locale.equals(locale)) {
1826                     // Don't churn a new Locale clone unless we're actually changing it
1827                     locale = (Locale) delta.locale.clone();
1828                 }
1829             }
1830         }
1831         if ((mask & ActivityInfo.CONFIG_LAYOUT_DIRECTION) != 0) {
1832             final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
1833             screenLayout = (screenLayout & ~SCREENLAYOUT_LAYOUTDIR_MASK) | deltaScreenLayoutDir;
1834         }
1835         if ((mask & ActivityInfo.CONFIG_LOCALE) != 0) {
1836             userSetLocale = delta.userSetLocale;
1837         }
1838         if ((mask & ActivityInfo.CONFIG_TOUCHSCREEN) != 0) {
1839             touchscreen = delta.touchscreen;
1840         }
1841         if ((mask & ActivityInfo.CONFIG_KEYBOARD) != 0) {
1842             keyboard = delta.keyboard;
1843         }
1844         if ((mask & ActivityInfo.CONFIG_KEYBOARD_HIDDEN) != 0) {
1845             keyboardHidden = delta.keyboardHidden;
1846             hardKeyboardHidden = delta.hardKeyboardHidden;
1847             navigationHidden = delta.navigationHidden;
1848         }
1849         if ((mask & ActivityInfo.CONFIG_NAVIGATION) != 0) {
1850             navigation = delta.navigation;
1851         }
1852         if ((mask & ActivityInfo.CONFIG_ORIENTATION) != 0) {
1853             orientation = delta.orientation;
1854         }
1855         if ((mask & ActivityInfo.CONFIG_SCREEN_LAYOUT) != 0) {
1856             // Not enough granularity for each component unfortunately.
1857             screenLayout = screenLayout | (delta.screenLayout & ~SCREENLAYOUT_LAYOUTDIR_MASK);
1858         }
1859         if ((mask & ActivityInfo.CONFIG_COLOR_MODE) != 0) {
1860             colorMode = delta.colorMode;
1861         }
1862         if ((mask & ActivityInfo.CONFIG_UI_MODE) != 0) {
1863             uiMode = delta.uiMode;
1864         }
1865         if ((mask & ActivityInfo.CONFIG_SCREEN_SIZE) != 0) {
1866             screenWidthDp = delta.screenWidthDp;
1867             screenHeightDp = delta.screenHeightDp;
1868         }
1869         if ((mask & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0) {
1870             smallestScreenWidthDp = delta.smallestScreenWidthDp;
1871         }
1872         if ((mask & ActivityInfo.CONFIG_DENSITY) != 0) {
1873             densityDpi = delta.densityDpi;
1874         }
1875         if ((mask & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) {
1876             assetsSeq = delta.assetsSeq;
1877         }
1878         if ((mask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0) {
1879             windowConfiguration.setTo(delta.windowConfiguration, windowMask);
1880         }
1881         if ((mask & ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT) != 0) {
1882             fontWeightAdjustment = delta.fontWeightAdjustment;
1883         }
1884         if ((mask & ActivityInfo.CONFIG_GRAMMATICAL_GENDER) != 0) {
1885             mGrammaticalGender = delta.mGrammaticalGender;
1886         }
1887     }
1888 
1889     /**
1890      * Return a bit mask of the differences between this Configuration
1891      * object and the given one.  Does not change the values of either.  Any
1892      * undefined fields in <var>delta</var> are ignored.
1893      * @return Returns a bit mask indicating which configuration
1894      * values have changed.
1895      */
diff(Configuration delta)1896     public @Config int diff(Configuration delta) {
1897         return diff(delta, false /* compareUndefined */, false /* publicOnly */);
1898     }
1899 
1900     /**
1901      * Returns the diff against the provided {@link Configuration} excluding values that would
1902      * publicly be equivalent, such as appBounds.
1903      * @param delta {@link Configuration} to compare to.
1904      *
1905      * TODO(b/36812336): Remove once appBounds has been moved out of Configuration.
1906      * {@hide}
1907      */
diffPublicOnly(Configuration delta)1908     public int diffPublicOnly(Configuration delta) {
1909         return diff(delta, false /* compareUndefined */, true /* publicOnly */);
1910     }
1911 
1912     /**
1913      * Variation of {@link #diff(Configuration)} with an option to skip checks for undefined values.
1914      *
1915      * @hide
1916      */
diff(Configuration delta, boolean compareUndefined, boolean publicOnly)1917     public int diff(Configuration delta, boolean compareUndefined, boolean publicOnly) {
1918         int changed = 0;
1919         if ((compareUndefined || delta.fontScale > 0) && fontScale != delta.fontScale) {
1920             changed |= ActivityInfo.CONFIG_FONT_SCALE;
1921         }
1922         if ((compareUndefined || delta.mcc != 0) && mcc != delta.mcc) {
1923             changed |= ActivityInfo.CONFIG_MCC;
1924         }
1925         if ((compareUndefined || delta.mnc != 0) && mnc != delta.mnc) {
1926             changed |= ActivityInfo.CONFIG_MNC;
1927         }
1928         fixUpLocaleList();
1929         delta.fixUpLocaleList();
1930         if ((compareUndefined || !delta.mLocaleList.isEmpty())
1931                 && !mLocaleList.equals(delta.mLocaleList)) {
1932             changed |= ActivityInfo.CONFIG_LOCALE;
1933             changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
1934         }
1935         final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
1936         if ((compareUndefined || deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED)
1937                 && deltaScreenLayoutDir != (screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) {
1938             changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
1939         }
1940         if ((compareUndefined || delta.touchscreen != TOUCHSCREEN_UNDEFINED)
1941                 && touchscreen != delta.touchscreen) {
1942             changed |= ActivityInfo.CONFIG_TOUCHSCREEN;
1943         }
1944         if ((compareUndefined || delta.keyboard != KEYBOARD_UNDEFINED)
1945                 && keyboard != delta.keyboard) {
1946             changed |= ActivityInfo.CONFIG_KEYBOARD;
1947         }
1948         if ((compareUndefined || delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED)
1949                 && keyboardHidden != delta.keyboardHidden) {
1950             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
1951         }
1952         if ((compareUndefined || delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED)
1953                 && hardKeyboardHidden != delta.hardKeyboardHidden) {
1954             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
1955         }
1956         if ((compareUndefined || delta.navigation != NAVIGATION_UNDEFINED)
1957                 && navigation != delta.navigation) {
1958             changed |= ActivityInfo.CONFIG_NAVIGATION;
1959         }
1960         if ((compareUndefined || delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED)
1961                 && navigationHidden != delta.navigationHidden) {
1962             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
1963         }
1964         if ((compareUndefined || delta.orientation != ORIENTATION_UNDEFINED)
1965                 && orientation != delta.orientation) {
1966             changed |= ActivityInfo.CONFIG_ORIENTATION;
1967         }
1968         if ((compareUndefined || getScreenLayoutNoDirection(delta.screenLayout) !=
1969                 (SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED))
1970                 && getScreenLayoutNoDirection(screenLayout) !=
1971                 getScreenLayoutNoDirection(delta.screenLayout)) {
1972             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
1973         }
1974         if ((compareUndefined ||
1975                      (delta.colorMode & COLOR_MODE_HDR_MASK) != COLOR_MODE_HDR_UNDEFINED)
1976                 && (colorMode & COLOR_MODE_HDR_MASK) !=
1977                         (delta.colorMode & COLOR_MODE_HDR_MASK)) {
1978             changed |= ActivityInfo.CONFIG_COLOR_MODE;
1979         }
1980         if ((compareUndefined ||
1981                      (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) !=
1982                              COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED)
1983                 && (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) !=
1984                         (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) {
1985             changed |= ActivityInfo.CONFIG_COLOR_MODE;
1986         }
1987         if ((compareUndefined || delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED))
1988                 && uiMode != delta.uiMode) {
1989             changed |= ActivityInfo.CONFIG_UI_MODE;
1990         }
1991         if ((compareUndefined || delta.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED)
1992                 && screenWidthDp != delta.screenWidthDp) {
1993             changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
1994         }
1995         if ((compareUndefined || delta.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED)
1996                 && screenHeightDp != delta.screenHeightDp) {
1997             changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
1998         }
1999         if ((compareUndefined || delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED)
2000                 && smallestScreenWidthDp != delta.smallestScreenWidthDp) {
2001             changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
2002         }
2003         if ((compareUndefined || delta.densityDpi != DENSITY_DPI_UNDEFINED)
2004                 && densityDpi != delta.densityDpi) {
2005             changed |= ActivityInfo.CONFIG_DENSITY;
2006         }
2007         if ((compareUndefined || delta.assetsSeq != ASSETS_SEQ_UNDEFINED)
2008                 && assetsSeq != delta.assetsSeq) {
2009             changed |= ActivityInfo.CONFIG_ASSETS_PATHS;
2010         }
2011 
2012         // WindowConfiguration differences aren't considered public...
2013         if (!publicOnly
2014                 && windowConfiguration.diff(delta.windowConfiguration, compareUndefined) != 0) {
2015             changed |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
2016         }
2017 
2018         if ((compareUndefined || delta.fontWeightAdjustment != FONT_WEIGHT_ADJUSTMENT_UNDEFINED)
2019                 && fontWeightAdjustment != delta.fontWeightAdjustment) {
2020             changed |= ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT;
2021         }
2022 
2023         if ((compareUndefined || delta.mGrammaticalGender != GRAMMATICAL_GENDER_UNDEFINED)
2024                 && mGrammaticalGender != delta.mGrammaticalGender) {
2025             changed |= ActivityInfo.CONFIG_GRAMMATICAL_GENDER;
2026         }
2027         return changed;
2028     }
2029 
2030     /**
2031      * Determines if a new resource needs to be loaded from the bit set of
2032      * configuration changes returned by {@link #updateFrom(Configuration)}.
2033      *
2034      * @param configChanges the mask of changes configurations as returned by
2035      *                      {@link #updateFrom(Configuration)}
2036      * @param interestingChanges the configuration changes that the resource
2037      *                           can handle as given in
2038      *                           {@link android.util.TypedValue#changingConfigurations}
2039      * @return {@code true} if the resource needs to be loaded, {@code false}
2040      *         otherwise
2041      */
needNewResources(@onfig int configChanges, @Config int interestingChanges)2042     public static boolean needNewResources(@Config int configChanges,
2043             @Config int interestingChanges) {
2044         // CONFIG_ASSETS_PATHS and CONFIG_FONT_SCALE are higher level configuration changes that
2045         // all resources are subject to change with.
2046         interestingChanges = interestingChanges | ActivityInfo.CONFIG_ASSETS_PATHS
2047                 | ActivityInfo.CONFIG_FONT_SCALE;
2048         return (configChanges & interestingChanges) != 0;
2049     }
2050 
2051     /**
2052      * @hide Return true if the sequence of 'other' is better than this.  Assumes
2053      * that 'this' is your current sequence and 'other' is a new one you have
2054      * received some how and want to compare with what you have.
2055      */
isOtherSeqNewer(Configuration other)2056     public boolean isOtherSeqNewer(Configuration other) {
2057         if (other == null) {
2058             // Validation check.
2059             return false;
2060         }
2061         if (other.seq == 0) {
2062             // If the other sequence is not specified, then we must assume
2063             // it is newer since we don't know any better.
2064             return true;
2065         }
2066         if (seq == 0) {
2067             // If this sequence is not specified, then we also consider the
2068             // other is better.  Yes we have a preference for other.  Sue us.
2069             return true;
2070         }
2071         int diff = other.seq - seq;
2072         if (Math.abs(diff) > 0x10000000) {
2073             // If there has been a sufficiently large jump, assume the
2074             // sequence has wrapped around.
2075             return diff < 0;
2076         }
2077         return diff > 0;
2078     }
2079 
2080     /**
2081      * Parcelable methods
2082      */
describeContents()2083     public int describeContents() {
2084         return 0;
2085     }
2086 
writeToParcel(Parcel dest, int flags)2087     public void writeToParcel(Parcel dest, int flags) {
2088         dest.writeFloat(fontScale);
2089         dest.writeInt(mcc);
2090         dest.writeInt(mnc);
2091 
2092         fixUpLocaleList();
2093         dest.writeTypedObject(mLocaleList, flags);
2094 
2095         if(userSetLocale) {
2096             dest.writeInt(1);
2097         } else {
2098             dest.writeInt(0);
2099         }
2100         dest.writeInt(touchscreen);
2101         dest.writeInt(keyboard);
2102         dest.writeInt(keyboardHidden);
2103         dest.writeInt(hardKeyboardHidden);
2104         dest.writeInt(navigation);
2105         dest.writeInt(navigationHidden);
2106         dest.writeInt(orientation);
2107         dest.writeInt(screenLayout);
2108         dest.writeInt(colorMode);
2109         dest.writeInt(uiMode);
2110         dest.writeInt(screenWidthDp);
2111         dest.writeInt(screenHeightDp);
2112         dest.writeInt(smallestScreenWidthDp);
2113         dest.writeInt(densityDpi);
2114         dest.writeInt(compatScreenWidthDp);
2115         dest.writeInt(compatScreenHeightDp);
2116         dest.writeInt(compatSmallestScreenWidthDp);
2117         windowConfiguration.writeToParcel(dest, flags);
2118         dest.writeInt(assetsSeq);
2119         dest.writeInt(seq);
2120         dest.writeInt(fontWeightAdjustment);
2121         dest.writeInt(mGrammaticalGender);
2122     }
2123 
readFromParcel(Parcel source)2124     public void readFromParcel(Parcel source) {
2125         fontScale = source.readFloat();
2126         mcc = source.readInt();
2127         mnc = source.readInt();
2128 
2129         mLocaleList = source.readTypedObject(LocaleList.CREATOR);
2130         locale = mLocaleList.get(0);
2131 
2132         userSetLocale = (source.readInt()==1);
2133         touchscreen = source.readInt();
2134         keyboard = source.readInt();
2135         keyboardHidden = source.readInt();
2136         hardKeyboardHidden = source.readInt();
2137         navigation = source.readInt();
2138         navigationHidden = source.readInt();
2139         orientation = source.readInt();
2140         screenLayout = source.readInt();
2141         colorMode = source.readInt();
2142         uiMode = source.readInt();
2143         screenWidthDp = source.readInt();
2144         screenHeightDp = source.readInt();
2145         smallestScreenWidthDp = source.readInt();
2146         densityDpi = source.readInt();
2147         compatScreenWidthDp = source.readInt();
2148         compatScreenHeightDp = source.readInt();
2149         compatSmallestScreenWidthDp = source.readInt();
2150         windowConfiguration.readFromParcel(source);
2151         assetsSeq = source.readInt();
2152         seq = source.readInt();
2153         fontWeightAdjustment = source.readInt();
2154         mGrammaticalGender = source.readInt();
2155     }
2156 
2157     public static final @android.annotation.NonNull Parcelable.Creator<Configuration> CREATOR
2158             = new Parcelable.Creator<Configuration>() {
2159         public Configuration createFromParcel(Parcel source) {
2160             return new Configuration(source);
2161         }
2162 
2163         public Configuration[] newArray(int size) {
2164             return new Configuration[size];
2165         }
2166     };
2167 
2168     /**
2169      * Construct this Configuration object, reading from the Parcel.
2170      */
Configuration(Parcel source)2171     private Configuration(Parcel source) {
2172         readFromParcel(source);
2173     }
2174 
2175 
2176     /**
2177      * Retuns whether the configuration is in night mode
2178      * @return true if night mode is active and false otherwise
2179      */
isNightModeActive()2180     public boolean isNightModeActive() {
2181         return (uiMode & UI_MODE_NIGHT_MASK) == UI_MODE_NIGHT_YES;
2182     }
2183 
compareTo(Configuration that)2184     public int compareTo(Configuration that) {
2185         int n;
2186         float a = this.fontScale;
2187         float b = that.fontScale;
2188         if (a < b) return -1;
2189         if (a > b) return 1;
2190         n = this.mcc - that.mcc;
2191         if (n != 0) return n;
2192         n = this.mnc - that.mnc;
2193         if (n != 0) return n;
2194 
2195         fixUpLocaleList();
2196         that.fixUpLocaleList();
2197         // for backward compatibility, we consider an empty locale list to be greater
2198         // than any non-empty locale list.
2199         if (this.mLocaleList.isEmpty()) {
2200             if (!that.mLocaleList.isEmpty()) return 1;
2201         } else if (that.mLocaleList.isEmpty()) {
2202             return -1;
2203         } else {
2204             final int minSize = Math.min(this.mLocaleList.size(), that.mLocaleList.size());
2205             for (int i = 0; i < minSize; ++i) {
2206                 final Locale thisLocale = this.mLocaleList.get(i);
2207                 final Locale thatLocale = that.mLocaleList.get(i);
2208                 n = thisLocale.getLanguage().compareTo(thatLocale.getLanguage());
2209                 if (n != 0) return n;
2210                 n = thisLocale.getCountry().compareTo(thatLocale.getCountry());
2211                 if (n != 0) return n;
2212                 n = thisLocale.getVariant().compareTo(thatLocale.getVariant());
2213                 if (n != 0) return n;
2214                 n = thisLocale.toLanguageTag().compareTo(thatLocale.toLanguageTag());
2215                 if (n != 0) return n;
2216             }
2217             n = this.mLocaleList.size() - that.mLocaleList.size();
2218             if (n != 0) return n;
2219         }
2220 
2221         n = this.mGrammaticalGender - that.mGrammaticalGender;
2222         if (n != 0) return n;
2223         n = this.touchscreen - that.touchscreen;
2224         if (n != 0) return n;
2225         n = this.keyboard - that.keyboard;
2226         if (n != 0) return n;
2227         n = this.keyboardHidden - that.keyboardHidden;
2228         if (n != 0) return n;
2229         n = this.hardKeyboardHidden - that.hardKeyboardHidden;
2230         if (n != 0) return n;
2231         n = this.navigation - that.navigation;
2232         if (n != 0) return n;
2233         n = this.navigationHidden - that.navigationHidden;
2234         if (n != 0) return n;
2235         n = this.orientation - that.orientation;
2236         if (n != 0) return n;
2237         n = this.colorMode - that.colorMode;
2238         if (n != 0) return n;
2239         n = this.screenLayout - that.screenLayout;
2240         if (n != 0) return n;
2241         n = this.uiMode - that.uiMode;
2242         if (n != 0) return n;
2243         n = this.screenWidthDp - that.screenWidthDp;
2244         if (n != 0) return n;
2245         n = this.screenHeightDp - that.screenHeightDp;
2246         if (n != 0) return n;
2247         n = this.smallestScreenWidthDp - that.smallestScreenWidthDp;
2248         if (n != 0) return n;
2249         n = this.densityDpi - that.densityDpi;
2250         if (n != 0) return n;
2251         n = this.assetsSeq - that.assetsSeq;
2252         if (n != 0) return n;
2253         n = windowConfiguration.compareTo(that.windowConfiguration);
2254         if (n != 0) return n;
2255         n = this.fontWeightAdjustment - that.fontWeightAdjustment;
2256         return n;
2257     }
2258 
equals(Configuration that)2259     public boolean equals(Configuration that) {
2260         if (that == null) return false;
2261         if (that == this) return true;
2262         return this.compareTo(that) == 0;
2263     }
2264 
equals(@ullable Object that)2265     public boolean equals(@Nullable Object that) {
2266         try {
2267             return equals((Configuration)that);
2268         } catch (ClassCastException e) {
2269         }
2270         return false;
2271     }
2272 
hashCode()2273     public int hashCode() {
2274         int result = 17;
2275         result = 31 * result + Float.floatToIntBits(fontScale);
2276         result = 31 * result + mcc;
2277         result = 31 * result + mnc;
2278         result = 31 * result + mLocaleList.hashCode();
2279         result = 31 * result + touchscreen;
2280         result = 31 * result + keyboard;
2281         result = 31 * result + keyboardHidden;
2282         result = 31 * result + hardKeyboardHidden;
2283         result = 31 * result + navigation;
2284         result = 31 * result + navigationHidden;
2285         result = 31 * result + orientation;
2286         result = 31 * result + screenLayout;
2287         result = 31 * result + colorMode;
2288         result = 31 * result + uiMode;
2289         result = 31 * result + screenWidthDp;
2290         result = 31 * result + screenHeightDp;
2291         result = 31 * result + smallestScreenWidthDp;
2292         result = 31 * result + densityDpi;
2293         result = 31 * result + assetsSeq;
2294         result = 31 * result + fontWeightAdjustment;
2295         result = 31 * result + mGrammaticalGender;
2296         return result;
2297     }
2298 
2299     /**
2300      * Returns the user preference for the grammatical gender. Will be
2301      * {@link #GRAMMATICAL_GENDER_NOT_SPECIFIED} or
2302      * {@link #GRAMMATICAL_GENDER_NEUTRAL} or
2303      * {@link #GRAMMATICAL_GENDER_FEMININE} or
2304      * {@link #GRAMMATICAL_GENDER_MASCULINE}.
2305      *
2306      * @return The preferred grammatical gender.
2307      */
2308     @GrammaticalGender
getGrammaticalGender()2309     public int getGrammaticalGender() {
2310         return mGrammaticalGender == GRAMMATICAL_GENDER_UNDEFINED
2311                 ? GRAMMATICAL_GENDER_NOT_SPECIFIED : mGrammaticalGender;
2312     }
2313 
2314     /**
2315      * Internal getter of grammatical gender, to get the raw value of grammatical gender,
2316      * which include {@link #GRAMMATICAL_GENDER_UNDEFINED}.
2317      * @hide
2318      */
2319 
getGrammaticalGenderRaw()2320     public int getGrammaticalGenderRaw() {
2321         return mGrammaticalGender;
2322     }
2323 
2324     /**
2325      * Sets the user preference for the grammatical gender. This is only for frameworks to easily
2326      * override the gender in the configuration. To update the grammatical gender for an application
2327      * use {@link GrammaticalInflectionManager#setRequestedApplicationGrammaticalGender(int)}.
2328      *
2329      * @param grammaticalGender The preferred grammatical gender.
2330      * @hide
2331      */
setGrammaticalGender(@rammaticalGender int grammaticalGender)2332     public void setGrammaticalGender(@GrammaticalGender int grammaticalGender) {
2333         mGrammaticalGender = grammaticalGender;
2334     }
2335 
2336     /**
2337      * Get the locale list. This is the preferred way for getting the locales (instead of using
2338      * the direct accessor to {@link #locale}, which would only provide the primary locale).
2339      *
2340      * @return The locale list.
2341      */
getLocales()2342     public @NonNull LocaleList getLocales() {
2343         fixUpLocaleList();
2344         return mLocaleList;
2345     }
2346 
2347     /**
2348      * Set the locale list. This is the preferred way for setting up the locales (instead of using
2349      * the direct accessor or {@link #setLocale(Locale)}). This will also set the layout direction
2350      * according to the first locale in the list.
2351      *
2352      * Note that the layout direction will always come from the first locale in the locale list,
2353      * even if the locale is not supported by the resources (the resources may only support
2354      * another locale further down the list which has a different direction).
2355      *
2356      * @param locales The locale list. If null, an empty LocaleList will be assigned.
2357      */
setLocales(@ullable LocaleList locales)2358     public void setLocales(@Nullable LocaleList locales) {
2359         mLocaleList = locales == null ? LocaleList.getEmptyLocaleList() : locales;
2360         locale = mLocaleList.get(0);
2361         setLayoutDirection(locale);
2362     }
2363 
2364     /**
2365      * Set the locale list to a list of just one locale. This will also set the layout direction
2366      * according to the locale.
2367      *
2368      * Note that after this is run, calling <code>.equals()</code> on the input locale and the
2369      * {@link #locale} attribute would return <code>true</code> if they are not null, but there is
2370      * no guarantee that they would be the same object.
2371      *
2372      * See also the note about layout direction in {@link #setLocales(LocaleList)}.
2373      *
2374      * @param loc The locale. Can be null.
2375      */
setLocale(@ullable Locale loc)2376     public void setLocale(@Nullable Locale loc) {
2377         setLocales(loc == null ? LocaleList.getEmptyLocaleList() : new LocaleList(loc));
2378     }
2379 
2380     /**
2381      * @hide
2382      *
2383      * Clears the locale without changing layout direction.
2384      */
clearLocales()2385     public void clearLocales() {
2386         mLocaleList = LocaleList.getEmptyLocaleList();
2387         locale = null;
2388     }
2389 
2390     /**
2391      * Return the layout direction. Will be either {@link View#LAYOUT_DIRECTION_LTR} or
2392      * {@link View#LAYOUT_DIRECTION_RTL}.
2393      *
2394      * @return Returns {@link View#LAYOUT_DIRECTION_RTL} if the configuration
2395      * is {@link #SCREENLAYOUT_LAYOUTDIR_RTL}, otherwise {@link View#LAYOUT_DIRECTION_LTR}.
2396      */
getLayoutDirection()2397     public int getLayoutDirection() {
2398         return (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK) == SCREENLAYOUT_LAYOUTDIR_RTL
2399                 ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
2400     }
2401 
2402     /**
2403      * Set the layout direction from a Locale.
2404      *
2405      * @param loc The Locale. If null will set the layout direction to
2406      * {@link View#LAYOUT_DIRECTION_LTR}. If not null will set it to the layout direction
2407      * corresponding to the Locale.
2408      *
2409      * @see View#LAYOUT_DIRECTION_LTR
2410      * @see View#LAYOUT_DIRECTION_RTL
2411      */
setLayoutDirection(Locale loc)2412     public void setLayoutDirection(Locale loc) {
2413         // There is a "1" difference between the configuration values for
2414         // layout direction and View constants for layout direction, just add "1".
2415         final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(loc);
2416         screenLayout = (screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK)|
2417                 (layoutDirection << SCREENLAYOUT_LAYOUTDIR_SHIFT);
2418     }
2419 
getScreenLayoutNoDirection(int screenLayout)2420     private static int getScreenLayoutNoDirection(int screenLayout) {
2421         return screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK;
2422     }
2423 
2424     /**
2425      * Return whether the screen has a round shape. Apps may choose to change styling based
2426      * on this property, such as the alignment or layout of text or informational icons.
2427      *
2428      * @return true if the screen is rounded, false otherwise
2429      */
isScreenRound()2430     public boolean isScreenRound() {
2431         return (screenLayout & SCREENLAYOUT_ROUND_MASK) == SCREENLAYOUT_ROUND_YES;
2432     }
2433 
2434     /**
2435      * Return whether the screen has a wide color gamut and wide color gamut rendering
2436      * is supported by this device.
2437      *
2438      * When true, it implies the screen is colorspace aware but not
2439      * necessarily color-managed. The final colors may still be changed by the
2440      * screen depending on user settings.
2441      *
2442      * @return true if the screen has a wide color gamut and wide color gamut rendering
2443      * is supported, false otherwise
2444      */
isScreenWideColorGamut()2445     public boolean isScreenWideColorGamut() {
2446         return (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) == COLOR_MODE_WIDE_COLOR_GAMUT_YES;
2447     }
2448 
2449     /**
2450      * Return whether the screen has a high dynamic range.
2451      *
2452      * @return true if the screen has a high dynamic range, false otherwise
2453      */
isScreenHdr()2454     public boolean isScreenHdr() {
2455         return (colorMode & COLOR_MODE_HDR_MASK) == COLOR_MODE_HDR_YES;
2456     }
2457 
2458     /**
2459      *
2460      * @hide
2461      */
localesToResourceQualifier(LocaleList locs)2462     public static String localesToResourceQualifier(LocaleList locs) {
2463         final StringBuilder sb = new StringBuilder();
2464         for (int i = 0; i < locs.size(); i++) {
2465             final Locale loc = locs.get(i);
2466             final int l = loc.getLanguage().length();
2467             if (l == 0) {
2468                 continue;
2469             }
2470             final int s = loc.getScript().length();
2471             final int c = loc.getCountry().length();
2472             final int v = loc.getVariant().length();
2473             // We ignore locale extensions, since they are not supported by AAPT
2474 
2475             if (sb.length() != 0) {
2476                 sb.append(",");
2477             }
2478             if (l == 2 && s == 0 && (c == 0 || c == 2) && v == 0) {
2479                 // Traditional locale format: xx or xx-rYY
2480                 sb.append(loc.getLanguage());
2481                 if (c == 2) {
2482                     sb.append("-r").append(loc.getCountry());
2483                 }
2484             } else {
2485                 sb.append("b+");
2486                 sb.append(loc.getLanguage());
2487                 if (s != 0) {
2488                     sb.append("+");
2489                     sb.append(loc.getScript());
2490                 }
2491                 if (c != 0) {
2492                     sb.append("+");
2493                     sb.append(loc.getCountry());
2494                 }
2495                 if (v != 0) {
2496                     sb.append("+");
2497                     sb.append(loc.getVariant());
2498                 }
2499             }
2500         }
2501         return sb.toString();
2502     }
2503 
2504 
2505     /**
2506      * Returns a string representation of the configuration that can be parsed
2507      * by build tools (like AAPT), without display metrics included
2508      *
2509      * @hide
2510      */
2511     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
resourceQualifierString(Configuration config)2512     public static String resourceQualifierString(Configuration config) {
2513         return resourceQualifierString(config, null);
2514     }
2515 
2516     /**
2517      * Returns a string representation of the configuration that can be parsed
2518      * by build tools (like AAPT).
2519      *
2520      * @hide
2521      */
resourceQualifierString(Configuration config, DisplayMetrics metrics)2522     public static String resourceQualifierString(Configuration config, DisplayMetrics metrics) {
2523         ArrayList<String> parts = new ArrayList<String>();
2524 
2525         if (config.mcc != 0) {
2526             parts.add("mcc" + config.mcc);
2527             if (config.mnc != 0) {
2528                 parts.add("mnc" + config.mnc);
2529             }
2530         }
2531 
2532         if (!config.mLocaleList.isEmpty()) {
2533             final String resourceQualifier = localesToResourceQualifier(config.mLocaleList);
2534             if (!resourceQualifier.isEmpty()) {
2535                 parts.add(resourceQualifier);
2536             }
2537         }
2538 
2539         switch (config.mGrammaticalGender) {
2540             case Configuration.GRAMMATICAL_GENDER_NEUTRAL:
2541                 parts.add("neuter");
2542                 break;
2543             case Configuration.GRAMMATICAL_GENDER_FEMININE:
2544                 parts.add("feminine");
2545                 break;
2546             case Configuration.GRAMMATICAL_GENDER_MASCULINE:
2547                 parts.add("masculine");
2548                 break;
2549             default:
2550                 break;
2551         }
2552 
2553         switch (config.screenLayout & Configuration.SCREENLAYOUT_LAYOUTDIR_MASK) {
2554             case Configuration.SCREENLAYOUT_LAYOUTDIR_LTR:
2555                 parts.add("ldltr");
2556                 break;
2557             case Configuration.SCREENLAYOUT_LAYOUTDIR_RTL:
2558                 parts.add("ldrtl");
2559                 break;
2560             default:
2561                 break;
2562         }
2563 
2564         if (config.smallestScreenWidthDp != 0) {
2565             parts.add("sw" + config.smallestScreenWidthDp + "dp");
2566         }
2567 
2568         if (config.screenWidthDp != 0) {
2569             parts.add("w" + config.screenWidthDp + "dp");
2570         }
2571 
2572         if (config.screenHeightDp != 0) {
2573             parts.add("h" + config.screenHeightDp + "dp");
2574         }
2575 
2576         switch (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) {
2577             case Configuration.SCREENLAYOUT_SIZE_SMALL:
2578                 parts.add("small");
2579                 break;
2580             case Configuration.SCREENLAYOUT_SIZE_NORMAL:
2581                 parts.add("normal");
2582                 break;
2583             case Configuration.SCREENLAYOUT_SIZE_LARGE:
2584                 parts.add("large");
2585                 break;
2586             case Configuration.SCREENLAYOUT_SIZE_XLARGE:
2587                 parts.add("xlarge");
2588                 break;
2589             default:
2590                 break;
2591         }
2592 
2593         switch (config.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK) {
2594             case Configuration.SCREENLAYOUT_LONG_YES:
2595                 parts.add("long");
2596                 break;
2597             case Configuration.SCREENLAYOUT_LONG_NO:
2598                 parts.add("notlong");
2599                 break;
2600             default:
2601                 break;
2602         }
2603 
2604         switch (config.screenLayout & Configuration.SCREENLAYOUT_ROUND_MASK) {
2605             case Configuration.SCREENLAYOUT_ROUND_YES:
2606                 parts.add("round");
2607                 break;
2608             case Configuration.SCREENLAYOUT_ROUND_NO:
2609                 parts.add("notround");
2610                 break;
2611             default:
2612                 break;
2613         }
2614 
2615         switch (config.colorMode & Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_MASK) {
2616             case Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_YES:
2617                 parts.add("widecg");
2618                 break;
2619             case Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_NO:
2620                 parts.add("nowidecg");
2621                 break;
2622             default:
2623                 break;
2624         }
2625 
2626         switch (config.colorMode & Configuration.COLOR_MODE_HDR_MASK) {
2627             case Configuration.COLOR_MODE_HDR_YES:
2628                 parts.add("highdr");
2629                 break;
2630             case Configuration.COLOR_MODE_HDR_NO:
2631                 parts.add("lowdr");
2632                 break;
2633             default:
2634                 break;
2635         }
2636 
2637         switch (config.orientation) {
2638             case Configuration.ORIENTATION_LANDSCAPE:
2639                 parts.add("land");
2640                 break;
2641             case Configuration.ORIENTATION_PORTRAIT:
2642                 parts.add("port");
2643                 break;
2644             default:
2645                 break;
2646         }
2647 
2648         final String uiModeTypeString =
2649                 getUiModeTypeString(config.uiMode & Configuration.UI_MODE_TYPE_MASK);
2650         if (uiModeTypeString != null) {
2651             parts.add(uiModeTypeString);
2652         }
2653 
2654         switch (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) {
2655             case Configuration.UI_MODE_NIGHT_YES:
2656                 parts.add("night");
2657                 break;
2658             case Configuration.UI_MODE_NIGHT_NO:
2659                 parts.add("notnight");
2660                 break;
2661             default:
2662                 break;
2663         }
2664 
2665         switch (config.densityDpi) {
2666             case DENSITY_DPI_UNDEFINED:
2667                 break;
2668             case 120:
2669                 parts.add("ldpi");
2670                 break;
2671             case 160:
2672                 parts.add("mdpi");
2673                 break;
2674             case 213:
2675                 parts.add("tvdpi");
2676                 break;
2677             case 240:
2678                 parts.add("hdpi");
2679                 break;
2680             case 320:
2681                 parts.add("xhdpi");
2682                 break;
2683             case 480:
2684                 parts.add("xxhdpi");
2685                 break;
2686             case 640:
2687                 parts.add("xxxhdpi");
2688                 break;
2689             case DENSITY_DPI_ANY:
2690                 parts.add("anydpi");
2691                 break;
2692             case DENSITY_DPI_NONE:
2693                 parts.add("nodpi");
2694                 break;
2695             default:
2696                 parts.add(config.densityDpi + "dpi");
2697                 break;
2698         }
2699 
2700         switch (config.touchscreen) {
2701             case Configuration.TOUCHSCREEN_NOTOUCH:
2702                 parts.add("notouch");
2703                 break;
2704             case Configuration.TOUCHSCREEN_FINGER:
2705                 parts.add("finger");
2706                 break;
2707             default:
2708                 break;
2709         }
2710 
2711         switch (config.keyboardHidden) {
2712             case Configuration.KEYBOARDHIDDEN_NO:
2713                 parts.add("keysexposed");
2714                 break;
2715             case Configuration.KEYBOARDHIDDEN_YES:
2716                 parts.add("keyshidden");
2717                 break;
2718             case Configuration.KEYBOARDHIDDEN_SOFT:
2719                 parts.add("keyssoft");
2720                 break;
2721             default:
2722                 break;
2723         }
2724 
2725         switch (config.keyboard) {
2726             case Configuration.KEYBOARD_NOKEYS:
2727                 parts.add("nokeys");
2728                 break;
2729             case Configuration.KEYBOARD_QWERTY:
2730                 parts.add("qwerty");
2731                 break;
2732             case Configuration.KEYBOARD_12KEY:
2733                 parts.add("12key");
2734                 break;
2735             default:
2736                 break;
2737         }
2738 
2739         switch (config.navigationHidden) {
2740             case Configuration.NAVIGATIONHIDDEN_NO:
2741                 parts.add("navexposed");
2742                 break;
2743             case Configuration.NAVIGATIONHIDDEN_YES:
2744                 parts.add("navhidden");
2745                 break;
2746             default:
2747                 break;
2748         }
2749 
2750         switch (config.navigation) {
2751             case Configuration.NAVIGATION_NONAV:
2752                 parts.add("nonav");
2753                 break;
2754             case Configuration.NAVIGATION_DPAD:
2755                 parts.add("dpad");
2756                 break;
2757             case Configuration.NAVIGATION_TRACKBALL:
2758                 parts.add("trackball");
2759                 break;
2760             case Configuration.NAVIGATION_WHEEL:
2761                 parts.add("wheel");
2762                 break;
2763             default:
2764                 break;
2765         }
2766 
2767         if (metrics != null) {
2768             final int width, height;
2769             if (metrics.widthPixels >= metrics.heightPixels) {
2770                 width = metrics.widthPixels;
2771                 height = metrics.heightPixels;
2772             } else {
2773                 //noinspection SuspiciousNameCombination
2774                 width = metrics.heightPixels;
2775                 //noinspection SuspiciousNameCombination
2776                 height = metrics.widthPixels;
2777             }
2778             parts.add(width + "x" + height);
2779         }
2780 
2781         parts.add("v" + Build.VERSION.RESOURCES_SDK_INT);
2782         return TextUtils.join("-", parts);
2783     }
2784 
2785     /**
2786      * @hide
2787      */
getUiModeTypeString(int uiModeType)2788     public static String getUiModeTypeString(int uiModeType) {
2789         switch (uiModeType) {
2790             case Configuration.UI_MODE_TYPE_APPLIANCE:
2791                 return "appliance";
2792             case Configuration.UI_MODE_TYPE_DESK:
2793                 return "desk";
2794             case Configuration.UI_MODE_TYPE_TELEVISION:
2795                 return "television";
2796             case Configuration.UI_MODE_TYPE_CAR:
2797                 return "car";
2798             case Configuration.UI_MODE_TYPE_WATCH:
2799                 return "watch";
2800             case Configuration.UI_MODE_TYPE_VR_HEADSET:
2801                 return "vrheadset";
2802             default:
2803                 return null;
2804         }
2805     }
2806 
2807     /**
2808      * Generate a delta Configuration between <code>base</code> and <code>change</code>. The
2809      * resulting delta can be used with {@link #updateFrom(Configuration)}.
2810      * <p />
2811      * Caveat: If the any of the Configuration's members becomes undefined, then
2812      * {@link #updateFrom(Configuration)} will treat it as a no-op and not update that member.
2813      *
2814      * This is fine for device configurations as no member is ever undefined.
2815      */
2816     @NonNull
generateDelta( @onNull Configuration base, @NonNull Configuration change)2817     public static Configuration generateDelta(
2818             @NonNull Configuration base, @NonNull Configuration change) {
2819         final Configuration delta = new Configuration();
2820         if (base.fontScale != change.fontScale) {
2821             delta.fontScale = change.fontScale;
2822         }
2823 
2824         if (base.mcc != change.mcc) {
2825             delta.mcc = change.mcc;
2826         }
2827 
2828         if (base.mnc != change.mnc) {
2829             delta.mnc = change.mnc;
2830         }
2831 
2832         base.fixUpLocaleList();
2833         change.fixUpLocaleList();
2834         if (!base.mLocaleList.equals(change.mLocaleList))  {
2835             delta.mLocaleList = change.mLocaleList;
2836             delta.locale = change.locale;
2837         }
2838 
2839         if (base.mGrammaticalGender != change.mGrammaticalGender) {
2840             delta.mGrammaticalGender = change.mGrammaticalGender;
2841         }
2842 
2843         if (base.touchscreen != change.touchscreen) {
2844             delta.touchscreen = change.touchscreen;
2845         }
2846 
2847         if (base.keyboard != change.keyboard) {
2848             delta.keyboard = change.keyboard;
2849         }
2850 
2851         if (base.keyboardHidden != change.keyboardHidden) {
2852             delta.keyboardHidden = change.keyboardHidden;
2853         }
2854 
2855         if (base.navigation != change.navigation) {
2856             delta.navigation = change.navigation;
2857         }
2858 
2859         if (base.navigationHidden != change.navigationHidden) {
2860             delta.navigationHidden = change.navigationHidden;
2861         }
2862 
2863         if (base.orientation != change.orientation) {
2864             delta.orientation = change.orientation;
2865         }
2866 
2867         if ((base.screenLayout & SCREENLAYOUT_SIZE_MASK) !=
2868                 (change.screenLayout & SCREENLAYOUT_SIZE_MASK)) {
2869             delta.screenLayout |= change.screenLayout & SCREENLAYOUT_SIZE_MASK;
2870         }
2871 
2872         if ((base.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK) !=
2873                 (change.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) {
2874             delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
2875         }
2876 
2877         if ((base.screenLayout & SCREENLAYOUT_LONG_MASK) !=
2878                 (change.screenLayout & SCREENLAYOUT_LONG_MASK)) {
2879             delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LONG_MASK;
2880         }
2881 
2882         if ((base.screenLayout & SCREENLAYOUT_ROUND_MASK) !=
2883                 (change.screenLayout & SCREENLAYOUT_ROUND_MASK)) {
2884             delta.screenLayout |= change.screenLayout & SCREENLAYOUT_ROUND_MASK;
2885         }
2886 
2887         if ((base.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) !=
2888                 (change.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) {
2889             delta.colorMode |= change.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK;
2890         }
2891 
2892         if ((base.colorMode & COLOR_MODE_HDR_MASK) !=
2893                 (change.colorMode & COLOR_MODE_HDR_MASK)) {
2894             delta.colorMode |= change.colorMode & COLOR_MODE_HDR_MASK;
2895         }
2896 
2897         if ((base.uiMode & UI_MODE_TYPE_MASK) != (change.uiMode & UI_MODE_TYPE_MASK)) {
2898             delta.uiMode |= change.uiMode & UI_MODE_TYPE_MASK;
2899         }
2900 
2901         if ((base.uiMode & UI_MODE_NIGHT_MASK) != (change.uiMode & UI_MODE_NIGHT_MASK)) {
2902             delta.uiMode |= change.uiMode & UI_MODE_NIGHT_MASK;
2903         }
2904 
2905         if (base.screenWidthDp != change.screenWidthDp) {
2906             delta.screenWidthDp = change.screenWidthDp;
2907         }
2908 
2909         if (base.screenHeightDp != change.screenHeightDp) {
2910             delta.screenHeightDp = change.screenHeightDp;
2911         }
2912 
2913         if (base.smallestScreenWidthDp != change.smallestScreenWidthDp) {
2914             delta.smallestScreenWidthDp = change.smallestScreenWidthDp;
2915         }
2916 
2917         if (base.densityDpi != change.densityDpi) {
2918             delta.densityDpi = change.densityDpi;
2919         }
2920 
2921         if (base.assetsSeq != change.assetsSeq) {
2922             delta.assetsSeq = change.assetsSeq;
2923         }
2924 
2925         if (!base.windowConfiguration.equals(change.windowConfiguration)) {
2926             delta.windowConfiguration.setTo(change.windowConfiguration);
2927         }
2928 
2929         if (base.fontWeightAdjustment != change.fontWeightAdjustment) {
2930             delta.fontWeightAdjustment = change.fontWeightAdjustment;
2931         }
2932         return delta;
2933     }
2934 
2935     private static final String XML_ATTR_FONT_SCALE = "fs";
2936     private static final String XML_ATTR_MCC = "mcc";
2937     private static final String XML_ATTR_MNC = "mnc";
2938     private static final String XML_ATTR_LOCALES = "locales";
2939     private static final String XML_ATTR_TOUCHSCREEN = "touch";
2940     private static final String XML_ATTR_KEYBOARD = "key";
2941     private static final String XML_ATTR_KEYBOARD_HIDDEN = "keyHid";
2942     private static final String XML_ATTR_HARD_KEYBOARD_HIDDEN = "hardKeyHid";
2943     private static final String XML_ATTR_NAVIGATION = "nav";
2944     private static final String XML_ATTR_NAVIGATION_HIDDEN = "navHid";
2945     private static final String XML_ATTR_ORIENTATION = "ori";
2946     private static final String XML_ATTR_ROTATION = "rot";
2947     private static final String XML_ATTR_SCREEN_LAYOUT = "scrLay";
2948     private static final String XML_ATTR_COLOR_MODE = "clrMod";
2949     private static final String XML_ATTR_UI_MODE = "ui";
2950     private static final String XML_ATTR_SCREEN_WIDTH = "width";
2951     private static final String XML_ATTR_SCREEN_HEIGHT = "height";
2952     private static final String XML_ATTR_SMALLEST_WIDTH = "sw";
2953     private static final String XML_ATTR_DENSITY = "density";
2954     private static final String XML_ATTR_APP_BOUNDS = "app_bounds";
2955     private static final String XML_ATTR_FONT_WEIGHT_ADJUSTMENT = "fontWeightAdjustment";
2956     private static final String XML_ATTR_GRAMMATICAL_GENDER = "grammaticalGender";
2957 
2958     /**
2959      * Reads the attributes corresponding to Configuration member fields from the Xml parser.
2960      * The parser is expected to be on a tag which has Configuration attributes.
2961      *
2962      * @param parser The Xml parser from which to read attributes.
2963      * @param configOut The Configuration to populate from the Xml attributes.
2964      * {@hide}
2965      */
readXmlAttrs(XmlPullParser parser, Configuration configOut)2966     public static void readXmlAttrs(XmlPullParser parser, Configuration configOut)
2967             throws XmlPullParserException, IOException {
2968         configOut.fontScale = Float.intBitsToFloat(
2969                 XmlUtils.readIntAttribute(parser, XML_ATTR_FONT_SCALE, 0));
2970         configOut.mcc = XmlUtils.readIntAttribute(parser, XML_ATTR_MCC, 0);
2971         configOut.mnc = XmlUtils.readIntAttribute(parser, XML_ATTR_MNC, 0);
2972 
2973         final String localesStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALES);
2974         configOut.mLocaleList = LocaleList.forLanguageTags(localesStr);
2975         configOut.locale = configOut.mLocaleList.get(0);
2976 
2977         configOut.touchscreen = XmlUtils.readIntAttribute(parser, XML_ATTR_TOUCHSCREEN,
2978                 TOUCHSCREEN_UNDEFINED);
2979         configOut.keyboard = XmlUtils.readIntAttribute(parser, XML_ATTR_KEYBOARD,
2980                 KEYBOARD_UNDEFINED);
2981         configOut.keyboardHidden = XmlUtils.readIntAttribute(parser, XML_ATTR_KEYBOARD_HIDDEN,
2982                 KEYBOARDHIDDEN_UNDEFINED);
2983         configOut.hardKeyboardHidden =
2984                 XmlUtils.readIntAttribute(parser, XML_ATTR_HARD_KEYBOARD_HIDDEN,
2985                         HARDKEYBOARDHIDDEN_UNDEFINED);
2986         configOut.navigation = XmlUtils.readIntAttribute(parser, XML_ATTR_NAVIGATION,
2987                 NAVIGATION_UNDEFINED);
2988         configOut.navigationHidden = XmlUtils.readIntAttribute(parser, XML_ATTR_NAVIGATION_HIDDEN,
2989                 NAVIGATIONHIDDEN_UNDEFINED);
2990         configOut.orientation = XmlUtils.readIntAttribute(parser, XML_ATTR_ORIENTATION,
2991                 ORIENTATION_UNDEFINED);
2992         configOut.screenLayout = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_LAYOUT,
2993                 SCREENLAYOUT_UNDEFINED);
2994         configOut.colorMode = XmlUtils.readIntAttribute(parser, XML_ATTR_COLOR_MODE,
2995                 COLOR_MODE_UNDEFINED);
2996         configOut.uiMode = XmlUtils.readIntAttribute(parser, XML_ATTR_UI_MODE, 0);
2997         configOut.screenWidthDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_WIDTH,
2998                 SCREEN_WIDTH_DP_UNDEFINED);
2999         configOut.screenHeightDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_HEIGHT,
3000                 SCREEN_HEIGHT_DP_UNDEFINED);
3001         configOut.smallestScreenWidthDp =
3002                 XmlUtils.readIntAttribute(parser, XML_ATTR_SMALLEST_WIDTH,
3003                         SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
3004         configOut.densityDpi = XmlUtils.readIntAttribute(parser, XML_ATTR_DENSITY,
3005                 DENSITY_DPI_UNDEFINED);
3006         configOut.fontWeightAdjustment = XmlUtils.readIntAttribute(parser,
3007                 XML_ATTR_FONT_WEIGHT_ADJUSTMENT, FONT_WEIGHT_ADJUSTMENT_UNDEFINED);
3008         configOut.mGrammaticalGender = XmlUtils.readIntAttribute(parser,
3009                 XML_ATTR_GRAMMATICAL_GENDER, GRAMMATICAL_GENDER_UNDEFINED);
3010 
3011         // For persistence, we don't care about assetsSeq and WindowConfiguration, so do not read it
3012         // out.
3013     }
3014 }
3015