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