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