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