• 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 current width of the available screen space, in dp units,
755      * corresponding to
756      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenWidthQualifier">screen
757      * width</a> resource qualifier.  Set to
758      * {@link #SCREEN_WIDTH_DP_UNDEFINED} if no width is specified.
759      */
760     public int screenWidthDp;
761 
762     /**
763      * Default value for {@link #screenHeightDp} indicating that no width
764      * has been specified.
765      */
766     public static final int SCREEN_HEIGHT_DP_UNDEFINED = 0;
767 
768     /**
769      * The current height of the available screen space, in dp units,
770      * corresponding to
771      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenHeightQualifier">screen
772      * height</a> resource qualifier.  Set to
773      * {@link #SCREEN_HEIGHT_DP_UNDEFINED} if no height is specified.
774      */
775     public int screenHeightDp;
776 
777     /**
778      * Default value for {@link #smallestScreenWidthDp} indicating that no width
779      * has been specified.
780      */
781     public static final int SMALLEST_SCREEN_WIDTH_DP_UNDEFINED = 0;
782 
783     /**
784      * The smallest screen size an application will see in normal operation,
785      * corresponding to
786      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#SmallestScreenWidthQualifier">smallest
787      * screen width</a> resource qualifier.
788      * This is the smallest value of both screenWidthDp and screenHeightDp
789      * in both portrait and landscape.  Set to
790      * {@link #SMALLEST_SCREEN_WIDTH_DP_UNDEFINED} if no width is specified.
791      */
792     public int smallestScreenWidthDp;
793 
794     /**
795      * Default value for {@link #densityDpi} indicating that no width
796      * has been specified.
797      */
798     public static final int DENSITY_DPI_UNDEFINED = 0;
799 
800     /**
801      * Value for {@link #densityDpi} for resources that scale to any density (vector drawables).
802      * {@hide}
803      */
804     public static final int DENSITY_DPI_ANY = 0xfffe;
805 
806     /**
807      * Value for {@link #densityDpi} for resources that are not meant to be scaled.
808      * {@hide}
809      */
810     public static final int DENSITY_DPI_NONE = 0xffff;
811 
812     /**
813      * The target screen density being rendered to,
814      * corresponding to
815      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#DensityQualifier">density</a>
816      * resource qualifier.  Set to
817      * {@link #DENSITY_DPI_UNDEFINED} if no density is specified.
818      */
819     public int densityDpi;
820 
821     /** @hide Hack to get this information from WM to app running in compat mode. */
822     public int compatScreenWidthDp;
823     /** @hide Hack to get this information from WM to app running in compat mode. */
824     public int compatScreenHeightDp;
825     /** @hide Hack to get this information from WM to app running in compat mode. */
826     public int compatSmallestScreenWidthDp;
827 
828     /**
829      * An undefined assetsSeq. This will not override an existing assetsSeq.
830      * @hide
831      */
832     public static final int ASSETS_SEQ_UNDEFINED = 0;
833 
834     /**
835      * Internal counter that allows us to piggyback off the configuration change mechanism to
836      * signal to apps that the the assets for an Application have changed. A difference in these
837      * between two Configurations will yield a diff flag of
838      * {@link ActivityInfo#CONFIG_ASSETS_PATHS}.
839      * @hide
840      */
841     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
842     @TestApi
843     public int assetsSeq;
844 
845     /**
846      * @hide Internal book-keeping.
847      */
848     @UnsupportedAppUsage
849     public int seq;
850 
851     /** @hide */
852     @IntDef(flag = true, prefix = { "NATIVE_CONFIG_" }, value = {
853             NATIVE_CONFIG_MCC,
854             NATIVE_CONFIG_MNC,
855             NATIVE_CONFIG_LOCALE,
856             NATIVE_CONFIG_TOUCHSCREEN,
857             NATIVE_CONFIG_KEYBOARD,
858             NATIVE_CONFIG_KEYBOARD_HIDDEN,
859             NATIVE_CONFIG_NAVIGATION,
860             NATIVE_CONFIG_ORIENTATION,
861             NATIVE_CONFIG_DENSITY,
862             NATIVE_CONFIG_SCREEN_SIZE,
863             NATIVE_CONFIG_VERSION,
864             NATIVE_CONFIG_SCREEN_LAYOUT,
865             NATIVE_CONFIG_UI_MODE,
866             NATIVE_CONFIG_SMALLEST_SCREEN_SIZE,
867             NATIVE_CONFIG_LAYOUTDIR,
868             NATIVE_CONFIG_COLOR_MODE,
869     })
870     @Retention(RetentionPolicy.SOURCE)
871     public @interface NativeConfig {}
872 
873     /** @hide Native-specific bit mask for MCC config; DO NOT USE UNLESS YOU ARE SURE. */
874     public static final int NATIVE_CONFIG_MCC = 0x0001;
875     /** @hide Native-specific bit mask for MNC config; DO NOT USE UNLESS YOU ARE SURE. */
876     public static final int NATIVE_CONFIG_MNC = 0x0002;
877     /** @hide Native-specific bit mask for LOCALE config; DO NOT USE UNLESS YOU ARE SURE. */
878     public static final int NATIVE_CONFIG_LOCALE = 0x0004;
879     /** @hide Native-specific bit mask for TOUCHSCREEN config; DO NOT USE UNLESS YOU ARE SURE. */
880     public static final int NATIVE_CONFIG_TOUCHSCREEN = 0x0008;
881     /** @hide Native-specific bit mask for KEYBOARD config; DO NOT USE UNLESS YOU ARE SURE. */
882     public static final int NATIVE_CONFIG_KEYBOARD = 0x0010;
883     /** @hide Native-specific bit mask for KEYBOARD_HIDDEN config; DO NOT USE UNLESS YOU
884      * ARE SURE. */
885     public static final int NATIVE_CONFIG_KEYBOARD_HIDDEN = 0x0020;
886     /** @hide Native-specific bit mask for NAVIGATION config; DO NOT USE UNLESS YOU ARE SURE. */
887     public static final int NATIVE_CONFIG_NAVIGATION = 0x0040;
888     /** @hide Native-specific bit mask for ORIENTATION config; DO NOT USE UNLESS YOU ARE SURE. */
889     public static final int NATIVE_CONFIG_ORIENTATION = 0x0080;
890     /** @hide Native-specific bit mask for DENSITY config; DO NOT USE UNLESS YOU ARE SURE. */
891     public static final int NATIVE_CONFIG_DENSITY = 0x0100;
892     /** @hide Native-specific bit mask for SCREEN_SIZE config; DO NOT USE UNLESS YOU ARE SURE. */
893     public static final int NATIVE_CONFIG_SCREEN_SIZE = 0x0200;
894     /** @hide Native-specific bit mask for VERSION config; DO NOT USE UNLESS YOU ARE SURE. */
895     public static final int NATIVE_CONFIG_VERSION = 0x0400;
896     /** @hide Native-specific bit mask for SCREEN_LAYOUT config; DO NOT USE UNLESS YOU ARE SURE. */
897     public static final int NATIVE_CONFIG_SCREEN_LAYOUT = 0x0800;
898     /** @hide Native-specific bit mask for UI_MODE config; DO NOT USE UNLESS YOU ARE SURE. */
899     public static final int NATIVE_CONFIG_UI_MODE = 0x1000;
900     /** @hide Native-specific bit mask for SMALLEST_SCREEN_SIZE config; DO NOT USE UNLESS YOU
901      * ARE SURE. */
902     public static final int NATIVE_CONFIG_SMALLEST_SCREEN_SIZE = 0x2000;
903     /** @hide Native-specific bit mask for LAYOUTDIR config ; DO NOT USE UNLESS YOU ARE SURE.*/
904     public static final int NATIVE_CONFIG_LAYOUTDIR = 0x4000;
905     /** @hide Native-specific bit mask for COLOR_MODE config ; DO NOT USE UNLESS YOU ARE SURE.*/
906     public static final int NATIVE_CONFIG_COLOR_MODE = 0x10000;
907 
908     /**
909      * <p>Construct an invalid Configuration. This state is only suitable for constructing a
910      * Configuration delta that will be applied to some valid Configuration object. In order to
911      * create a valid standalone Configuration, you must call {@link #setToDefaults}. </p>
912      *
913      * <p>Example:</p>
914      * <pre class="prettyprint">
915      *     Configuration validConfig = new Configuration();
916      *     validConfig.setToDefaults();
917      *
918      *     Configuration deltaOnlyConfig = new Configuration();
919      *     deltaOnlyConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
920      *
921      *     validConfig.updateFrom(deltaOnlyConfig);
922      * </pre>
923      */
Configuration()924     public Configuration() {
925         unset();
926     }
927 
928     /**
929      * Makes a deep copy suitable for modification.
930      */
Configuration(Configuration o)931     public Configuration(Configuration o) {
932         setTo(o);
933     }
934 
935     /* This brings mLocaleList in sync with locale in case a user of the older API who doesn't know
936      * about setLocales() has changed locale directly. */
fixUpLocaleList()937     private void fixUpLocaleList() {
938         if ((locale == null && !mLocaleList.isEmpty()) ||
939                 (locale != null && !locale.equals(mLocaleList.get(0)))) {
940             mLocaleList = locale == null ? LocaleList.getEmptyLocaleList() : new LocaleList(locale);
941         }
942     }
943 
944     /**
945      * Sets the fields in this object to those in the given Configuration.
946      *
947      * @param o The Configuration object used to set the values of this Configuration's fields.
948      */
setTo(Configuration o)949     public void setTo(Configuration o) {
950         fontScale = o.fontScale;
951         mcc = o.mcc;
952         mnc = o.mnc;
953         if (o.locale == null) {
954             locale = null;
955         } else if (!o.locale.equals(locale)) {
956             // Only clone a new Locale instance if we need to:  the clone() is
957             // both CPU and GC intensive.
958             locale = (Locale) o.locale.clone();
959         }
960         o.fixUpLocaleList();
961         mLocaleList = o.mLocaleList;
962         userSetLocale = o.userSetLocale;
963         touchscreen = o.touchscreen;
964         keyboard = o.keyboard;
965         keyboardHidden = o.keyboardHidden;
966         hardKeyboardHidden = o.hardKeyboardHidden;
967         navigation = o.navigation;
968         navigationHidden = o.navigationHidden;
969         orientation = o.orientation;
970         screenLayout = o.screenLayout;
971         colorMode = o.colorMode;
972         uiMode = o.uiMode;
973         screenWidthDp = o.screenWidthDp;
974         screenHeightDp = o.screenHeightDp;
975         smallestScreenWidthDp = o.smallestScreenWidthDp;
976         densityDpi = o.densityDpi;
977         compatScreenWidthDp = o.compatScreenWidthDp;
978         compatScreenHeightDp = o.compatScreenHeightDp;
979         compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp;
980         assetsSeq = o.assetsSeq;
981         seq = o.seq;
982         windowConfiguration.setTo(o.windowConfiguration);
983         fontWeightAdjustment = o.fontWeightAdjustment;
984     }
985 
toString()986     public String toString() {
987         StringBuilder sb = new StringBuilder(128);
988         sb.append("{");
989         sb.append(fontScale);
990         sb.append(" ");
991         if (mcc != 0) {
992             sb.append(mcc);
993             sb.append("mcc");
994         } else {
995             sb.append("?mcc");
996         }
997         if (mnc != 0) {
998             sb.append(mnc);
999             sb.append("mnc");
1000         } else {
1001             sb.append("?mnc");
1002         }
1003         fixUpLocaleList();
1004         if (!mLocaleList.isEmpty()) {
1005             sb.append(" ");
1006             sb.append(mLocaleList);
1007         } else {
1008             sb.append(" ?localeList");
1009         }
1010         int layoutDir = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK);
1011         switch (layoutDir) {
1012             case SCREENLAYOUT_LAYOUTDIR_UNDEFINED: sb.append(" ?layoutDir"); break;
1013             case SCREENLAYOUT_LAYOUTDIR_LTR: sb.append(" ldltr"); break;
1014             case SCREENLAYOUT_LAYOUTDIR_RTL: sb.append(" ldrtl"); break;
1015             default: sb.append(" layoutDir=");
1016                 sb.append(layoutDir >> SCREENLAYOUT_LAYOUTDIR_SHIFT); break;
1017         }
1018         if (smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
1019             sb.append(" sw"); sb.append(smallestScreenWidthDp); sb.append("dp");
1020         } else {
1021             sb.append(" ?swdp");
1022         }
1023         if (screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) {
1024             sb.append(" w"); sb.append(screenWidthDp); sb.append("dp");
1025         } else {
1026             sb.append(" ?wdp");
1027         }
1028         if (screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) {
1029             sb.append(" h"); sb.append(screenHeightDp); sb.append("dp");
1030         } else {
1031             sb.append(" ?hdp");
1032         }
1033         if (densityDpi != DENSITY_DPI_UNDEFINED) {
1034             sb.append(" "); sb.append(densityDpi); sb.append("dpi");
1035         } else {
1036             sb.append(" ?density");
1037         }
1038         switch ((screenLayout&SCREENLAYOUT_SIZE_MASK)) {
1039             case SCREENLAYOUT_SIZE_UNDEFINED: sb.append(" ?lsize"); break;
1040             case SCREENLAYOUT_SIZE_SMALL: sb.append(" smll"); break;
1041             case SCREENLAYOUT_SIZE_NORMAL: sb.append(" nrml"); break;
1042             case SCREENLAYOUT_SIZE_LARGE: sb.append(" lrg"); break;
1043             case SCREENLAYOUT_SIZE_XLARGE: sb.append(" xlrg"); break;
1044             default: sb.append(" layoutSize=");
1045                     sb.append(screenLayout&SCREENLAYOUT_SIZE_MASK); break;
1046         }
1047         switch ((screenLayout&SCREENLAYOUT_LONG_MASK)) {
1048             case SCREENLAYOUT_LONG_UNDEFINED: sb.append(" ?long"); break;
1049             case SCREENLAYOUT_LONG_NO: /* not-long is not interesting to print */ break;
1050             case SCREENLAYOUT_LONG_YES: sb.append(" long"); break;
1051             default: sb.append(" layoutLong=");
1052                     sb.append(screenLayout&SCREENLAYOUT_LONG_MASK); break;
1053         }
1054         switch ((colorMode &COLOR_MODE_HDR_MASK)) {
1055             case COLOR_MODE_HDR_UNDEFINED: sb.append(" ?ldr"); break; // most likely not HDR
1056             case COLOR_MODE_HDR_NO: /* ldr is not interesting to print */ break;
1057             case COLOR_MODE_HDR_YES: sb.append(" hdr"); break;
1058             default: sb.append(" dynamicRange=");
1059                 sb.append(colorMode &COLOR_MODE_HDR_MASK); break;
1060         }
1061         switch ((colorMode &COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) {
1062             case COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED: sb.append(" ?wideColorGamut"); break;
1063             case COLOR_MODE_WIDE_COLOR_GAMUT_NO: /* not wide is not interesting to print */ break;
1064             case COLOR_MODE_WIDE_COLOR_GAMUT_YES: sb.append(" widecg"); break;
1065             default: sb.append(" wideColorGamut=");
1066                 sb.append(colorMode &COLOR_MODE_WIDE_COLOR_GAMUT_MASK); break;
1067         }
1068         switch (orientation) {
1069             case ORIENTATION_UNDEFINED: sb.append(" ?orien"); break;
1070             case ORIENTATION_LANDSCAPE: sb.append(" land"); break;
1071             case ORIENTATION_PORTRAIT: sb.append(" port"); break;
1072             default: sb.append(" orien="); sb.append(orientation); break;
1073         }
1074         switch ((uiMode&UI_MODE_TYPE_MASK)) {
1075             case UI_MODE_TYPE_UNDEFINED: sb.append(" ?uimode"); break;
1076             case UI_MODE_TYPE_NORMAL: /* normal is not interesting to print */ break;
1077             case UI_MODE_TYPE_DESK: sb.append(" desk"); break;
1078             case UI_MODE_TYPE_CAR: sb.append(" car"); break;
1079             case UI_MODE_TYPE_TELEVISION: sb.append(" television"); break;
1080             case UI_MODE_TYPE_APPLIANCE: sb.append(" appliance"); break;
1081             case UI_MODE_TYPE_WATCH: sb.append(" watch"); break;
1082             case UI_MODE_TYPE_VR_HEADSET: sb.append(" vrheadset"); break;
1083             default: sb.append(" uimode="); sb.append(uiMode&UI_MODE_TYPE_MASK); break;
1084         }
1085         switch ((uiMode&UI_MODE_NIGHT_MASK)) {
1086             case UI_MODE_NIGHT_UNDEFINED: sb.append(" ?night"); break;
1087             case UI_MODE_NIGHT_NO: /* not-night is not interesting to print */ break;
1088             case UI_MODE_NIGHT_YES: sb.append(" night"); break;
1089             default: sb.append(" night="); sb.append(uiMode&UI_MODE_NIGHT_MASK); break;
1090         }
1091         switch (touchscreen) {
1092             case TOUCHSCREEN_UNDEFINED: sb.append(" ?touch"); break;
1093             case TOUCHSCREEN_NOTOUCH: sb.append(" -touch"); break;
1094             case TOUCHSCREEN_STYLUS: sb.append(" stylus"); break;
1095             case TOUCHSCREEN_FINGER: sb.append(" finger"); break;
1096             default: sb.append(" touch="); sb.append(touchscreen); break;
1097         }
1098         switch (keyboard) {
1099             case KEYBOARD_UNDEFINED: sb.append(" ?keyb"); break;
1100             case KEYBOARD_NOKEYS: sb.append(" -keyb"); break;
1101             case KEYBOARD_QWERTY: sb.append(" qwerty"); break;
1102             case KEYBOARD_12KEY: sb.append(" 12key"); break;
1103             default: sb.append(" keys="); sb.append(keyboard); break;
1104         }
1105         switch (keyboardHidden) {
1106             case KEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break;
1107             case KEYBOARDHIDDEN_NO: sb.append("/v"); break;
1108             case KEYBOARDHIDDEN_YES: sb.append("/h"); break;
1109             case KEYBOARDHIDDEN_SOFT: sb.append("/s"); break;
1110             default: sb.append("/"); sb.append(keyboardHidden); break;
1111         }
1112         switch (hardKeyboardHidden) {
1113             case HARDKEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break;
1114             case HARDKEYBOARDHIDDEN_NO: sb.append("/v"); break;
1115             case HARDKEYBOARDHIDDEN_YES: sb.append("/h"); break;
1116             default: sb.append("/"); sb.append(hardKeyboardHidden); break;
1117         }
1118         switch (navigation) {
1119             case NAVIGATION_UNDEFINED: sb.append(" ?nav"); break;
1120             case NAVIGATION_NONAV: sb.append(" -nav"); break;
1121             case NAVIGATION_DPAD: sb.append(" dpad"); break;
1122             case NAVIGATION_TRACKBALL: sb.append(" tball"); break;
1123             case NAVIGATION_WHEEL: sb.append(" wheel"); break;
1124             default: sb.append(" nav="); sb.append(navigation); break;
1125         }
1126         switch (navigationHidden) {
1127             case NAVIGATIONHIDDEN_UNDEFINED: sb.append("/?"); break;
1128             case NAVIGATIONHIDDEN_NO: sb.append("/v"); break;
1129             case NAVIGATIONHIDDEN_YES: sb.append("/h"); break;
1130             default: sb.append("/"); sb.append(navigationHidden); break;
1131         }
1132         sb.append(" winConfig="); sb.append(windowConfiguration);
1133         if (assetsSeq != 0) {
1134             sb.append(" as.").append(assetsSeq);
1135         }
1136         if (seq != 0) {
1137             sb.append(" s.").append(seq);
1138         }
1139         if (fontWeightAdjustment != FONT_WEIGHT_ADJUSTMENT_UNDEFINED) {
1140             sb.append(" fontWeightAdjustment=");
1141             sb.append(fontWeightAdjustment);
1142         } else {
1143             sb.append(" ?fontWeightAdjustment");
1144         }
1145         sb.append('}');
1146         return sb.toString();
1147     }
1148 
1149     /**
1150      * Write to a protocol buffer output stream.
1151      * Protocol buffer message definition at {@link android.content.ConfigurationProto}
1152      * Has the option to ignore fields that don't need to be persisted to disk.
1153      *
1154      * @param protoOutputStream Stream to write the Configuration object to.
1155      * @param fieldId           Field Id of the Configuration as defined in the parent message
1156      * @param persisted         Note if this proto will be persisted to disk
1157      * @param critical          If true, reduce amount of data written.
1158      * @hide
1159      */
dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean persisted, boolean critical)1160     public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean persisted,
1161             boolean critical) {
1162         final long token = protoOutputStream.start(fieldId);
1163         if (!critical) {
1164             protoOutputStream.write(FONT_SCALE, fontScale);
1165             protoOutputStream.write(MCC, mcc);
1166             protoOutputStream.write(MNC, mnc);
1167             if (mLocaleList != null) {
1168                 protoOutputStream.write(LOCALE_LIST, mLocaleList.toLanguageTags());
1169             }
1170             protoOutputStream.write(SCREEN_LAYOUT, screenLayout);
1171             protoOutputStream.write(COLOR_MODE, colorMode);
1172             protoOutputStream.write(TOUCHSCREEN, touchscreen);
1173             protoOutputStream.write(KEYBOARD, keyboard);
1174             protoOutputStream.write(KEYBOARD_HIDDEN, keyboardHidden);
1175             protoOutputStream.write(HARD_KEYBOARD_HIDDEN, hardKeyboardHidden);
1176             protoOutputStream.write(NAVIGATION, navigation);
1177             protoOutputStream.write(NAVIGATION_HIDDEN, navigationHidden);
1178             protoOutputStream.write(UI_MODE, uiMode);
1179             protoOutputStream.write(SMALLEST_SCREEN_WIDTH_DP, smallestScreenWidthDp);
1180             protoOutputStream.write(DENSITY_DPI, densityDpi);
1181             // For persistence, we do not care about window configuration
1182             if (!persisted && windowConfiguration != null) {
1183                 windowConfiguration.dumpDebug(protoOutputStream, WINDOW_CONFIGURATION);
1184             }
1185             protoOutputStream.write(FONT_WEIGHT_ADJUSTMENT, fontWeightAdjustment);
1186         }
1187         protoOutputStream.write(ORIENTATION, orientation);
1188         protoOutputStream.write(SCREEN_WIDTH_DP, screenWidthDp);
1189         protoOutputStream.write(SCREEN_HEIGHT_DP, screenHeightDp);
1190         protoOutputStream.end(token);
1191     }
1192 
1193     /**
1194      * Write to a protocol buffer output stream.
1195      * Protocol buffer message definition at {@link android.content.ConfigurationProto}
1196      *
1197      * @param protoOutputStream Stream to write the Configuration object to.
1198      * @param fieldId           Field Id of the Configuration as defined in the parent message
1199      * @hide
1200      */
dumpDebug(ProtoOutputStream protoOutputStream, long fieldId)1201     public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId) {
1202         dumpDebug(protoOutputStream, fieldId, false /* persisted */, false /* critical */);
1203     }
1204 
1205     /**
1206      * Write to a protocol buffer output stream.
1207      * Protocol buffer message definition at {@link android.content.ConfigurationProto}
1208      *
1209      * @param protoOutputStream Stream to write the Configuration object to.
1210      * @param fieldId           Field Id of the Configuration as defined in the parent message
1211      * @param critical          If true, reduce amount of data written.
1212      * @hide
1213      */
dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean critical)1214     public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean critical) {
1215         dumpDebug(protoOutputStream, fieldId, false /* persisted */, critical);
1216     }
1217 
1218     /**
1219      * Read from a protocol buffer output stream.
1220      * Protocol buffer message definition at {@link android.content.ConfigurationProto}
1221      *
1222      * @param protoInputStream Stream to read the Configuration object from.
1223      * @param fieldId          Field Id of the Configuration as defined in the parent message
1224      * @hide
1225      */
readFromProto(ProtoInputStream protoInputStream, long fieldId)1226     public void readFromProto(ProtoInputStream protoInputStream, long fieldId) throws IOException {
1227         final long token = protoInputStream.start(fieldId);
1228         final List<Locale> list = new ArrayList();
1229         try {
1230             while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
1231                 switch (protoInputStream.getFieldNumber()) {
1232                     case (int) FONT_SCALE:
1233                         fontScale = protoInputStream.readFloat(FONT_SCALE);
1234                         break;
1235                     case (int) MCC:
1236                         mcc = protoInputStream.readInt(MCC);
1237                         break;
1238                     case (int) MNC:
1239                         mnc = protoInputStream.readInt(MNC);
1240                         break;
1241                     case (int) LOCALES:
1242                         // Parse the Locale here to handle all the repeated Locales
1243                         // The LocaleList will be created when the message is completed
1244                         final long localeToken = protoInputStream.start(LOCALES);
1245                         String language = "";
1246                         String country = "";
1247                         String variant = "";
1248                         String script = "";
1249                         try {
1250                             while (protoInputStream.nextField()
1251                                     != ProtoInputStream.NO_MORE_FIELDS) {
1252                                 switch (protoInputStream.getFieldNumber()) {
1253                                     case (int) LocaleProto.LANGUAGE:
1254                                         language = protoInputStream.readString(
1255                                                 LocaleProto.LANGUAGE);
1256                                         break;
1257                                     case (int) LocaleProto.COUNTRY:
1258                                         country = protoInputStream.readString(LocaleProto.COUNTRY);
1259                                         break;
1260                                     case (int) LocaleProto.VARIANT:
1261                                         variant = protoInputStream.readString(LocaleProto.VARIANT);
1262                                         break;
1263                                     case (int) LocaleProto.SCRIPT:
1264                                         script = protoInputStream.readString(LocaleProto.SCRIPT);
1265                                         break;
1266                                 }
1267                             }
1268                         } catch (WireTypeMismatchException wtme) {
1269                             // rethrow for caller deal with
1270                             throw wtme;
1271                         } finally {
1272                             protoInputStream.end(localeToken);
1273                             try {
1274                                 final Locale locale = new Locale.Builder()
1275                                                         .setLanguage(language)
1276                                                         .setRegion(country)
1277                                                         .setVariant(variant)
1278                                                         .setScript(script)
1279                                                         .build();
1280                                 // Log a WTF here if a repeated locale is found to avoid throwing an
1281                                 // exception in system server when LocaleList is created below
1282                                 final int inListIndex = list.indexOf(locale);
1283                                 if (inListIndex != -1) {
1284                                     Slog.wtf(TAG, "Repeated locale (" + list.get(inListIndex) + ")"
1285                                             + " found when trying to add: " + locale.toString());
1286                                 } else {
1287                                     list.add(locale);
1288                                 }
1289                             } catch (IllformedLocaleException e) {
1290                                 Slog.e(TAG, "readFromProto error building locale with: "
1291                                         + "language-" + language + ";country-" + country
1292                                         + ";variant-" + variant + ";script-" + script);
1293                             }
1294                         }
1295                         break;
1296                     case (int) SCREEN_LAYOUT:
1297                         screenLayout = protoInputStream.readInt(SCREEN_LAYOUT);
1298                         break;
1299                     case (int) COLOR_MODE:
1300                         colorMode = protoInputStream.readInt(COLOR_MODE);
1301                         break;
1302                     case (int) TOUCHSCREEN:
1303                         touchscreen = protoInputStream.readInt(TOUCHSCREEN);
1304                         break;
1305                     case (int) KEYBOARD:
1306                         keyboard = protoInputStream.readInt(KEYBOARD);
1307                         break;
1308                     case (int) KEYBOARD_HIDDEN:
1309                         keyboardHidden = protoInputStream.readInt(KEYBOARD_HIDDEN);
1310                         break;
1311                     case (int) HARD_KEYBOARD_HIDDEN:
1312                         hardKeyboardHidden = protoInputStream.readInt(HARD_KEYBOARD_HIDDEN);
1313                         break;
1314                     case (int) NAVIGATION:
1315                         navigation = protoInputStream.readInt(NAVIGATION);
1316                         break;
1317                     case (int) NAVIGATION_HIDDEN:
1318                         navigationHidden = protoInputStream.readInt(NAVIGATION_HIDDEN);
1319                         break;
1320                     case (int) ORIENTATION:
1321                         orientation = protoInputStream.readInt(ORIENTATION);
1322                         break;
1323                     case (int) UI_MODE:
1324                         uiMode = protoInputStream.readInt(UI_MODE);
1325                         break;
1326                     case (int) SCREEN_WIDTH_DP:
1327                         screenWidthDp = protoInputStream.readInt(SCREEN_WIDTH_DP);
1328                         break;
1329                     case (int) SCREEN_HEIGHT_DP:
1330                         screenHeightDp = protoInputStream.readInt(SCREEN_HEIGHT_DP);
1331                         break;
1332                     case (int) SMALLEST_SCREEN_WIDTH_DP:
1333                         smallestScreenWidthDp = protoInputStream.readInt(SMALLEST_SCREEN_WIDTH_DP);
1334                         break;
1335                     case (int) DENSITY_DPI:
1336                         densityDpi = protoInputStream.readInt(DENSITY_DPI);
1337                         break;
1338                     case (int) WINDOW_CONFIGURATION:
1339                         windowConfiguration.readFromProto(protoInputStream, WINDOW_CONFIGURATION);
1340                         break;
1341                     case (int) LOCALE_LIST:
1342                         try {
1343                             setLocales(LocaleList.forLanguageTags(protoInputStream.readString(
1344                                     LOCALE_LIST)));
1345                         } catch (Exception e) {
1346                             Slog.e(TAG, "error parsing locale list in configuration.", e);
1347                         }
1348                         break;
1349                     case (int) FONT_WEIGHT_ADJUSTMENT:
1350                         fontWeightAdjustment = protoInputStream.readInt(FONT_WEIGHT_ADJUSTMENT);
1351                         break;
1352                 }
1353             }
1354         } finally {
1355             // Let caller handle any exceptions
1356             if (list.size() > 0) {
1357                 //Create the LocaleList from the collected Locales
1358                 setLocales(new LocaleList(list.toArray(new Locale[list.size()])));
1359             }
1360             protoInputStream.end(token);
1361         }
1362     }
1363 
1364     /**
1365      * Write full {@link android.content.ResourcesConfigurationProto} to protocol buffer output
1366      * stream.
1367      *
1368      * @param protoOutputStream Stream to write the Configuration object to.
1369      * @param fieldId           Field Id of the Configuration as defined in the parent message
1370      * @param metrics           Current display information
1371      * @hide
1372      */
writeResConfigToProto(ProtoOutputStream protoOutputStream, long fieldId, DisplayMetrics metrics)1373     public void writeResConfigToProto(ProtoOutputStream protoOutputStream, long fieldId,
1374             DisplayMetrics metrics) {
1375         final int width, height;
1376         if (metrics.widthPixels >= metrics.heightPixels) {
1377             width = metrics.widthPixels;
1378             height = metrics.heightPixels;
1379         } else {
1380             //noinspection SuspiciousNameCombination
1381             width = metrics.heightPixels;
1382             //noinspection SuspiciousNameCombination
1383             height = metrics.widthPixels;
1384         }
1385 
1386         final long token = protoOutputStream.start(fieldId);
1387         dumpDebug(protoOutputStream, CONFIGURATION);
1388         protoOutputStream.write(SDK_VERSION, Build.VERSION.RESOURCES_SDK_INT);
1389         protoOutputStream.write(SCREEN_WIDTH_PX, width);
1390         protoOutputStream.write(SCREEN_HEIGHT_PX, height);
1391         protoOutputStream.end(token);
1392     }
1393 
1394     /**
1395      * Convert the UI mode to a human readable format.
1396      * @hide
1397      */
uiModeToString(int uiMode)1398     public static String uiModeToString(int uiMode) {
1399         switch (uiMode) {
1400             case UI_MODE_TYPE_UNDEFINED:
1401                 return "UI_MODE_TYPE_UNDEFINED";
1402             case UI_MODE_TYPE_NORMAL:
1403                 return "UI_MODE_TYPE_NORMAL";
1404             case UI_MODE_TYPE_DESK:
1405                 return "UI_MODE_TYPE_DESK";
1406             case UI_MODE_TYPE_CAR:
1407                 return "UI_MODE_TYPE_CAR";
1408             case UI_MODE_TYPE_TELEVISION:
1409                 return "UI_MODE_TYPE_TELEVISION";
1410             case UI_MODE_TYPE_APPLIANCE:
1411                 return "UI_MODE_TYPE_APPLIANCE";
1412             case UI_MODE_TYPE_WATCH:
1413                 return "UI_MODE_TYPE_WATCH";
1414             case UI_MODE_TYPE_VR_HEADSET:
1415                 return "UI_MODE_TYPE_VR_HEADSET";
1416             default:
1417                 return Integer.toString(uiMode);
1418         }
1419     }
1420 
1421     /**
1422      * Set this object to the system defaults.
1423      */
setToDefaults()1424     public void setToDefaults() {
1425         fontScale = 1;
1426         mcc = mnc = 0;
1427         mLocaleList = LocaleList.getEmptyLocaleList();
1428         locale = null;
1429         userSetLocale = false;
1430         touchscreen = TOUCHSCREEN_UNDEFINED;
1431         keyboard = KEYBOARD_UNDEFINED;
1432         keyboardHidden = KEYBOARDHIDDEN_UNDEFINED;
1433         hardKeyboardHidden = HARDKEYBOARDHIDDEN_UNDEFINED;
1434         navigation = NAVIGATION_UNDEFINED;
1435         navigationHidden = NAVIGATIONHIDDEN_UNDEFINED;
1436         orientation = ORIENTATION_UNDEFINED;
1437         screenLayout = SCREENLAYOUT_UNDEFINED;
1438         colorMode = COLOR_MODE_UNDEFINED;
1439         uiMode = UI_MODE_TYPE_UNDEFINED;
1440         screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
1441         screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
1442         smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
1443         densityDpi = DENSITY_DPI_UNDEFINED;
1444         assetsSeq = ASSETS_SEQ_UNDEFINED;
1445         seq = 0;
1446         windowConfiguration.setToDefaults();
1447         fontWeightAdjustment = FONT_WEIGHT_ADJUSTMENT_UNDEFINED;
1448     }
1449 
1450     /**
1451      * Set this object to completely undefined.
1452      * @hide
1453      */
unset()1454     public void unset() {
1455         setToDefaults();
1456         fontScale = 0;
1457     }
1458 
1459     /** {@hide} */
1460     @UnsupportedAppUsage
makeDefault()1461     @Deprecated public void makeDefault() {
1462         setToDefaults();
1463     }
1464 
1465     /**
1466      * Copies the fields from delta into this Configuration object, keeping
1467      * track of which ones have changed. Any undefined fields in {@code delta}
1468      * are ignored and not copied in to the current Configuration.
1469      *
1470      * @return a bit mask of the changed fields, as per {@link #diff}
1471      */
updateFrom(@onNull Configuration delta)1472     public @Config int updateFrom(@NonNull Configuration delta) {
1473         int changed = 0;
1474         if (delta.fontScale > 0 && fontScale != delta.fontScale) {
1475             changed |= ActivityInfo.CONFIG_FONT_SCALE;
1476             fontScale = delta.fontScale;
1477         }
1478         if (delta.mcc != 0 && mcc != delta.mcc) {
1479             changed |= ActivityInfo.CONFIG_MCC;
1480             mcc = delta.mcc;
1481         }
1482         if (delta.mnc != 0 && mnc != delta.mnc) {
1483             changed |= ActivityInfo.CONFIG_MNC;
1484             mnc = delta.mnc;
1485         }
1486         fixUpLocaleList();
1487         delta.fixUpLocaleList();
1488         if (!delta.mLocaleList.isEmpty() && !mLocaleList.equals(delta.mLocaleList)) {
1489             changed |= ActivityInfo.CONFIG_LOCALE;
1490             mLocaleList = delta.mLocaleList;
1491             // delta.locale can't be null, since delta.mLocaleList is not empty.
1492             if (!delta.locale.equals(locale)) {
1493                 locale = (Locale) delta.locale.clone();
1494                 // If locale has changed, then layout direction is also changed ...
1495                 changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
1496                 // ... and we need to update the layout direction (represented by the first
1497                 // 2 most significant bits in screenLayout).
1498                 setLayoutDirection(locale);
1499             }
1500         }
1501         final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
1502         if (deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED &&
1503                 deltaScreenLayoutDir != (screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) {
1504             screenLayout = (screenLayout & ~SCREENLAYOUT_LAYOUTDIR_MASK) | deltaScreenLayoutDir;
1505             changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
1506         }
1507         if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
1508         {
1509             changed |= ActivityInfo.CONFIG_LOCALE;
1510             userSetLocale = true;
1511         }
1512         if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
1513                 && touchscreen != delta.touchscreen) {
1514             changed |= ActivityInfo.CONFIG_TOUCHSCREEN;
1515             touchscreen = delta.touchscreen;
1516         }
1517         if (delta.keyboard != KEYBOARD_UNDEFINED
1518                 && keyboard != delta.keyboard) {
1519             changed |= ActivityInfo.CONFIG_KEYBOARD;
1520             keyboard = delta.keyboard;
1521         }
1522         if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED
1523                 && keyboardHidden != delta.keyboardHidden) {
1524             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
1525             keyboardHidden = delta.keyboardHidden;
1526         }
1527         if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED
1528                 && hardKeyboardHidden != delta.hardKeyboardHidden) {
1529             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
1530             hardKeyboardHidden = delta.hardKeyboardHidden;
1531         }
1532         if (delta.navigation != NAVIGATION_UNDEFINED
1533                 && navigation != delta.navigation) {
1534             changed |= ActivityInfo.CONFIG_NAVIGATION;
1535             navigation = delta.navigation;
1536         }
1537         if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED
1538                 && navigationHidden != delta.navigationHidden) {
1539             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
1540             navigationHidden = delta.navigationHidden;
1541         }
1542         if (delta.orientation != ORIENTATION_UNDEFINED
1543                 && orientation != delta.orientation) {
1544             changed |= ActivityInfo.CONFIG_ORIENTATION;
1545             orientation = delta.orientation;
1546         }
1547         if (((delta.screenLayout & SCREENLAYOUT_SIZE_MASK) != SCREENLAYOUT_SIZE_UNDEFINED)
1548                 && (delta.screenLayout & SCREENLAYOUT_SIZE_MASK)
1549                 != (screenLayout & SCREENLAYOUT_SIZE_MASK)) {
1550             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
1551             screenLayout = (screenLayout & ~SCREENLAYOUT_SIZE_MASK)
1552                     | (delta.screenLayout & SCREENLAYOUT_SIZE_MASK);
1553         }
1554         if (((delta.screenLayout & SCREENLAYOUT_LONG_MASK) != SCREENLAYOUT_LONG_UNDEFINED)
1555                 && (delta.screenLayout & SCREENLAYOUT_LONG_MASK)
1556                 != (screenLayout & SCREENLAYOUT_LONG_MASK)) {
1557             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
1558             screenLayout = (screenLayout & ~SCREENLAYOUT_LONG_MASK)
1559                     | (delta.screenLayout & SCREENLAYOUT_LONG_MASK);
1560         }
1561         if (((delta.screenLayout & SCREENLAYOUT_ROUND_MASK) != SCREENLAYOUT_ROUND_UNDEFINED)
1562                 && (delta.screenLayout & SCREENLAYOUT_ROUND_MASK)
1563                 != (screenLayout & SCREENLAYOUT_ROUND_MASK)) {
1564             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
1565             screenLayout = (screenLayout & ~SCREENLAYOUT_ROUND_MASK)
1566                     | (delta.screenLayout & SCREENLAYOUT_ROUND_MASK);
1567         }
1568         if ((delta.screenLayout & SCREENLAYOUT_COMPAT_NEEDED)
1569                 != (screenLayout & SCREENLAYOUT_COMPAT_NEEDED)
1570                 && delta.screenLayout != 0) {
1571             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
1572             screenLayout = (screenLayout & ~SCREENLAYOUT_COMPAT_NEEDED)
1573                 | (delta.screenLayout & SCREENLAYOUT_COMPAT_NEEDED);
1574         }
1575 
1576         if (((delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) !=
1577                      COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED)
1578                 && (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)
1579                 != (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) {
1580             changed |= ActivityInfo.CONFIG_COLOR_MODE;
1581             colorMode = (colorMode & ~COLOR_MODE_WIDE_COLOR_GAMUT_MASK)
1582                     | (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK);
1583         }
1584 
1585         if (((delta.colorMode & COLOR_MODE_HDR_MASK) != COLOR_MODE_HDR_UNDEFINED)
1586                 && (delta.colorMode & COLOR_MODE_HDR_MASK)
1587                 != (colorMode & COLOR_MODE_HDR_MASK)) {
1588             changed |= ActivityInfo.CONFIG_COLOR_MODE;
1589             colorMode = (colorMode & ~COLOR_MODE_HDR_MASK)
1590                     | (delta.colorMode & COLOR_MODE_HDR_MASK);
1591         }
1592 
1593         if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED)
1594                 && uiMode != delta.uiMode) {
1595             changed |= ActivityInfo.CONFIG_UI_MODE;
1596             if ((delta.uiMode&UI_MODE_TYPE_MASK) != UI_MODE_TYPE_UNDEFINED) {
1597                 uiMode = (uiMode&~UI_MODE_TYPE_MASK)
1598                         | (delta.uiMode&UI_MODE_TYPE_MASK);
1599             }
1600             if ((delta.uiMode&UI_MODE_NIGHT_MASK) != UI_MODE_NIGHT_UNDEFINED) {
1601                 uiMode = (uiMode&~UI_MODE_NIGHT_MASK)
1602                         | (delta.uiMode&UI_MODE_NIGHT_MASK);
1603             }
1604         }
1605         if (delta.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED
1606                 && screenWidthDp != delta.screenWidthDp) {
1607             changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
1608             screenWidthDp = delta.screenWidthDp;
1609         }
1610         if (delta.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED
1611                 && screenHeightDp != delta.screenHeightDp) {
1612             changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
1613             screenHeightDp = delta.screenHeightDp;
1614         }
1615         if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
1616                 && smallestScreenWidthDp != delta.smallestScreenWidthDp) {
1617             changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
1618             smallestScreenWidthDp = delta.smallestScreenWidthDp;
1619         }
1620         if (delta.densityDpi != DENSITY_DPI_UNDEFINED &&
1621                 densityDpi != delta.densityDpi) {
1622             changed |= ActivityInfo.CONFIG_DENSITY;
1623             densityDpi = delta.densityDpi;
1624         }
1625         if (delta.compatScreenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) {
1626             compatScreenWidthDp = delta.compatScreenWidthDp;
1627         }
1628         if (delta.compatScreenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) {
1629             compatScreenHeightDp = delta.compatScreenHeightDp;
1630         }
1631         if (delta.compatSmallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
1632             compatSmallestScreenWidthDp = delta.compatSmallestScreenWidthDp;
1633         }
1634         if (delta.assetsSeq != ASSETS_SEQ_UNDEFINED && delta.assetsSeq != assetsSeq) {
1635             changed |= ActivityInfo.CONFIG_ASSETS_PATHS;
1636             assetsSeq = delta.assetsSeq;
1637         }
1638         if (delta.seq != 0) {
1639             seq = delta.seq;
1640         }
1641         if (windowConfiguration.updateFrom(delta.windowConfiguration) != 0) {
1642             changed |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
1643         }
1644 
1645         if (delta.fontWeightAdjustment != FONT_WEIGHT_ADJUSTMENT_UNDEFINED
1646                 && delta.fontWeightAdjustment != fontWeightAdjustment) {
1647             changed |= ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT;
1648             fontWeightAdjustment = delta.fontWeightAdjustment;
1649         }
1650 
1651         return changed;
1652     }
1653 
1654     /**
1655      * Copies the fields specified by mask from delta into this Configuration object. This will
1656      * copy anything allowed by the mask (including undefined values).
1657      * @hide
1658      */
setTo(@onNull Configuration delta, @Config int mask, @WindowConfiguration.WindowConfig int windowMask)1659     public void setTo(@NonNull Configuration delta, @Config int mask,
1660             @WindowConfiguration.WindowConfig int windowMask) {
1661         if ((mask & ActivityInfo.CONFIG_FONT_SCALE) != 0) {
1662             fontScale = delta.fontScale;
1663         }
1664         if ((mask & ActivityInfo.CONFIG_MCC) != 0) {
1665             mcc = delta.mcc;
1666         }
1667         if ((mask & ActivityInfo.CONFIG_MNC) != 0) {
1668             mnc = delta.mnc;
1669         }
1670         if ((mask & ActivityInfo.CONFIG_LOCALE) != 0) {
1671             mLocaleList = delta.mLocaleList;
1672             if (!mLocaleList.isEmpty()) {
1673                 if (!delta.locale.equals(locale)) {
1674                     // Don't churn a new Locale clone unless we're actually changing it
1675                     locale = (Locale) delta.locale.clone();
1676                 }
1677             }
1678         }
1679         if ((mask & ActivityInfo.CONFIG_LAYOUT_DIRECTION) != 0) {
1680             final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
1681             screenLayout = (screenLayout & ~SCREENLAYOUT_LAYOUTDIR_MASK) | deltaScreenLayoutDir;
1682         }
1683         if ((mask & ActivityInfo.CONFIG_LOCALE) != 0) {
1684             userSetLocale = delta.userSetLocale;
1685         }
1686         if ((mask & ActivityInfo.CONFIG_TOUCHSCREEN) != 0) {
1687             touchscreen = delta.touchscreen;
1688         }
1689         if ((mask & ActivityInfo.CONFIG_KEYBOARD) != 0) {
1690             keyboard = delta.keyboard;
1691         }
1692         if ((mask & ActivityInfo.CONFIG_KEYBOARD_HIDDEN) != 0) {
1693             keyboardHidden = delta.keyboardHidden;
1694             hardKeyboardHidden = delta.hardKeyboardHidden;
1695             navigationHidden = delta.navigationHidden;
1696         }
1697         if ((mask & ActivityInfo.CONFIG_NAVIGATION) != 0) {
1698             navigation = delta.navigation;
1699         }
1700         if ((mask & ActivityInfo.CONFIG_ORIENTATION) != 0) {
1701             orientation = delta.orientation;
1702         }
1703         if ((mask & ActivityInfo.CONFIG_SCREEN_LAYOUT) != 0) {
1704             // Not enough granularity for each component unfortunately.
1705             screenLayout = screenLayout | (delta.screenLayout & ~SCREENLAYOUT_LAYOUTDIR_MASK);
1706         }
1707         if ((mask & ActivityInfo.CONFIG_COLOR_MODE) != 0) {
1708             colorMode = delta.colorMode;
1709         }
1710         if ((mask & ActivityInfo.CONFIG_UI_MODE) != 0) {
1711             uiMode = delta.uiMode;
1712         }
1713         if ((mask & ActivityInfo.CONFIG_SCREEN_SIZE) != 0) {
1714             screenWidthDp = delta.screenWidthDp;
1715             screenHeightDp = delta.screenHeightDp;
1716         }
1717         if ((mask & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0) {
1718             smallestScreenWidthDp = delta.smallestScreenWidthDp;
1719         }
1720         if ((mask & ActivityInfo.CONFIG_DENSITY) != 0) {
1721             densityDpi = delta.densityDpi;
1722         }
1723         if ((mask & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) {
1724             assetsSeq = delta.assetsSeq;
1725         }
1726         if ((mask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0) {
1727             windowConfiguration.setTo(delta.windowConfiguration, windowMask);
1728         }
1729         if ((mask & ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT) != 0) {
1730             fontWeightAdjustment = delta.fontWeightAdjustment;
1731         }
1732     }
1733 
1734     /**
1735      * Return a bit mask of the differences between this Configuration
1736      * object and the given one.  Does not change the values of either.  Any
1737      * undefined fields in <var>delta</var> are ignored.
1738      * @return Returns a bit mask indicating which configuration
1739      * values has changed, containing any combination of
1740      * {@link android.content.pm.ActivityInfo#CONFIG_FONT_SCALE
1741      * PackageManager.ActivityInfo.CONFIG_FONT_SCALE},
1742      * {@link android.content.pm.ActivityInfo#CONFIG_MCC
1743      * PackageManager.ActivityInfo.CONFIG_MCC},
1744      * {@link android.content.pm.ActivityInfo#CONFIG_MNC
1745      * PackageManager.ActivityInfo.CONFIG_MNC},
1746      * {@link android.content.pm.ActivityInfo#CONFIG_LOCALE
1747      * PackageManager.ActivityInfo.CONFIG_LOCALE},
1748      * {@link android.content.pm.ActivityInfo#CONFIG_TOUCHSCREEN
1749      * PackageManager.ActivityInfo.CONFIG_TOUCHSCREEN},
1750      * {@link android.content.pm.ActivityInfo#CONFIG_KEYBOARD
1751      * PackageManager.ActivityInfo.CONFIG_KEYBOARD},
1752      * {@link android.content.pm.ActivityInfo#CONFIG_NAVIGATION
1753      * PackageManager.ActivityInfo.CONFIG_NAVIGATION},
1754      * {@link android.content.pm.ActivityInfo#CONFIG_ORIENTATION
1755      * PackageManager.ActivityInfo.CONFIG_ORIENTATION},
1756      * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_LAYOUT
1757      * PackageManager.ActivityInfo.CONFIG_SCREEN_LAYOUT}, or
1758      * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_SIZE
1759      * PackageManager.ActivityInfo.CONFIG_SCREEN_SIZE}, or
1760      * {@link android.content.pm.ActivityInfo#CONFIG_SMALLEST_SCREEN_SIZE
1761      * PackageManager.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE}.
1762      * {@link android.content.pm.ActivityInfo#CONFIG_LAYOUT_DIRECTION
1763      * PackageManager.ActivityInfo.CONFIG_LAYOUT_DIRECTION}.
1764      * {@link android.content.pm.ActivityInfo#CONFIG_FONT_WEIGHT_ADJUSTMENT
1765      *  PackageManager.ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT.
1766      */
diff(Configuration delta)1767     public int diff(Configuration delta) {
1768         return diff(delta, false /* compareUndefined */, false /* publicOnly */);
1769     }
1770 
1771     /**
1772      * Returns the diff against the provided {@link Configuration} excluding values that would
1773      * publicly be equivalent, such as appBounds.
1774      * @param delta {@link Configuration} to compare to.
1775      *
1776      * TODO(b/36812336): Remove once appBounds has been moved out of Configuration.
1777      * {@hide}
1778      */
diffPublicOnly(Configuration delta)1779     public int diffPublicOnly(Configuration delta) {
1780         return diff(delta, false /* compareUndefined */, true /* publicOnly */);
1781     }
1782 
1783     /**
1784      * Variation of {@link #diff(Configuration)} with an option to skip checks for undefined values.
1785      *
1786      * @hide
1787      */
diff(Configuration delta, boolean compareUndefined, boolean publicOnly)1788     public int diff(Configuration delta, boolean compareUndefined, boolean publicOnly) {
1789         int changed = 0;
1790         if ((compareUndefined || delta.fontScale > 0) && fontScale != delta.fontScale) {
1791             changed |= ActivityInfo.CONFIG_FONT_SCALE;
1792         }
1793         if ((compareUndefined || delta.mcc != 0) && mcc != delta.mcc) {
1794             changed |= ActivityInfo.CONFIG_MCC;
1795         }
1796         if ((compareUndefined || delta.mnc != 0) && mnc != delta.mnc) {
1797             changed |= ActivityInfo.CONFIG_MNC;
1798         }
1799         fixUpLocaleList();
1800         delta.fixUpLocaleList();
1801         if ((compareUndefined || !delta.mLocaleList.isEmpty())
1802                 && !mLocaleList.equals(delta.mLocaleList)) {
1803             changed |= ActivityInfo.CONFIG_LOCALE;
1804             changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
1805         }
1806         final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
1807         if ((compareUndefined || deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED)
1808                 && deltaScreenLayoutDir != (screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) {
1809             changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
1810         }
1811         if ((compareUndefined || delta.touchscreen != TOUCHSCREEN_UNDEFINED)
1812                 && touchscreen != delta.touchscreen) {
1813             changed |= ActivityInfo.CONFIG_TOUCHSCREEN;
1814         }
1815         if ((compareUndefined || delta.keyboard != KEYBOARD_UNDEFINED)
1816                 && keyboard != delta.keyboard) {
1817             changed |= ActivityInfo.CONFIG_KEYBOARD;
1818         }
1819         if ((compareUndefined || delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED)
1820                 && keyboardHidden != delta.keyboardHidden) {
1821             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
1822         }
1823         if ((compareUndefined || delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED)
1824                 && hardKeyboardHidden != delta.hardKeyboardHidden) {
1825             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
1826         }
1827         if ((compareUndefined || delta.navigation != NAVIGATION_UNDEFINED)
1828                 && navigation != delta.navigation) {
1829             changed |= ActivityInfo.CONFIG_NAVIGATION;
1830         }
1831         if ((compareUndefined || delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED)
1832                 && navigationHidden != delta.navigationHidden) {
1833             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
1834         }
1835         if ((compareUndefined || delta.orientation != ORIENTATION_UNDEFINED)
1836                 && orientation != delta.orientation) {
1837             changed |= ActivityInfo.CONFIG_ORIENTATION;
1838         }
1839         if ((compareUndefined || getScreenLayoutNoDirection(delta.screenLayout) !=
1840                 (SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED))
1841                 && getScreenLayoutNoDirection(screenLayout) !=
1842                 getScreenLayoutNoDirection(delta.screenLayout)) {
1843             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
1844         }
1845         if ((compareUndefined ||
1846                      (delta.colorMode & COLOR_MODE_HDR_MASK) != COLOR_MODE_HDR_UNDEFINED)
1847                 && (colorMode & COLOR_MODE_HDR_MASK) !=
1848                         (delta.colorMode & COLOR_MODE_HDR_MASK)) {
1849             changed |= ActivityInfo.CONFIG_COLOR_MODE;
1850         }
1851         if ((compareUndefined ||
1852                      (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) !=
1853                              COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED)
1854                 && (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) !=
1855                         (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) {
1856             changed |= ActivityInfo.CONFIG_COLOR_MODE;
1857         }
1858         if ((compareUndefined || delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED))
1859                 && uiMode != delta.uiMode) {
1860             changed |= ActivityInfo.CONFIG_UI_MODE;
1861         }
1862         if ((compareUndefined || delta.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED)
1863                 && screenWidthDp != delta.screenWidthDp) {
1864             changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
1865         }
1866         if ((compareUndefined || delta.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED)
1867                 && screenHeightDp != delta.screenHeightDp) {
1868             changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
1869         }
1870         if ((compareUndefined || delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED)
1871                 && smallestScreenWidthDp != delta.smallestScreenWidthDp) {
1872             changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
1873         }
1874         if ((compareUndefined || delta.densityDpi != DENSITY_DPI_UNDEFINED)
1875                 && densityDpi != delta.densityDpi) {
1876             changed |= ActivityInfo.CONFIG_DENSITY;
1877         }
1878         if ((compareUndefined || delta.assetsSeq != ASSETS_SEQ_UNDEFINED)
1879                 && assetsSeq != delta.assetsSeq) {
1880             changed |= ActivityInfo.CONFIG_ASSETS_PATHS;
1881         }
1882 
1883         // WindowConfiguration differences aren't considered public...
1884         if (!publicOnly
1885                 && windowConfiguration.diff(delta.windowConfiguration, compareUndefined) != 0) {
1886             changed |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
1887         }
1888 
1889         if ((compareUndefined || delta.fontWeightAdjustment != FONT_WEIGHT_ADJUSTMENT_UNDEFINED)
1890                 && fontWeightAdjustment != delta.fontWeightAdjustment) {
1891             changed |= ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT;
1892         }
1893         return changed;
1894     }
1895 
1896     /**
1897      * Determines if a new resource needs to be loaded from the bit set of
1898      * configuration changes returned by {@link #updateFrom(Configuration)}.
1899      *
1900      * @param configChanges the mask of changes configurations as returned by
1901      *                      {@link #updateFrom(Configuration)}
1902      * @param interestingChanges the configuration changes that the resource
1903      *                           can handle as given in
1904      *                           {@link android.util.TypedValue#changingConfigurations}
1905      * @return {@code true} if the resource needs to be loaded, {@code false}
1906      *         otherwise
1907      */
needNewResources(@onfig int configChanges, @Config int interestingChanges)1908     public static boolean needNewResources(@Config int configChanges,
1909             @Config int interestingChanges) {
1910         // CONFIG_ASSETS_PATHS and CONFIG_FONT_SCALE are higher level configuration changes that
1911         // all resources are subject to change with.
1912         interestingChanges = interestingChanges | ActivityInfo.CONFIG_ASSETS_PATHS
1913                 | ActivityInfo.CONFIG_FONT_SCALE;
1914         return (configChanges & interestingChanges) != 0;
1915     }
1916 
1917     /**
1918      * @hide Return true if the sequence of 'other' is better than this.  Assumes
1919      * that 'this' is your current sequence and 'other' is a new one you have
1920      * received some how and want to compare with what you have.
1921      */
isOtherSeqNewer(Configuration other)1922     public boolean isOtherSeqNewer(Configuration other) {
1923         if (other == null) {
1924             // Validation check.
1925             return false;
1926         }
1927         if (other.seq == 0) {
1928             // If the other sequence is not specified, then we must assume
1929             // it is newer since we don't know any better.
1930             return true;
1931         }
1932         if (seq == 0) {
1933             // If this sequence is not specified, then we also consider the
1934             // other is better.  Yes we have a preference for other.  Sue us.
1935             return true;
1936         }
1937         int diff = other.seq - seq;
1938         if (diff > 0x10000) {
1939             // If there has been a sufficiently large jump, assume the
1940             // sequence has wrapped around.
1941             return false;
1942         }
1943         return diff > 0;
1944     }
1945 
1946     /**
1947      * Parcelable methods
1948      */
describeContents()1949     public int describeContents() {
1950         return 0;
1951     }
1952 
writeToParcel(Parcel dest, int flags)1953     public void writeToParcel(Parcel dest, int flags) {
1954         dest.writeFloat(fontScale);
1955         dest.writeInt(mcc);
1956         dest.writeInt(mnc);
1957 
1958         fixUpLocaleList();
1959         dest.writeTypedObject(mLocaleList, flags);
1960 
1961         if(userSetLocale) {
1962             dest.writeInt(1);
1963         } else {
1964             dest.writeInt(0);
1965         }
1966         dest.writeInt(touchscreen);
1967         dest.writeInt(keyboard);
1968         dest.writeInt(keyboardHidden);
1969         dest.writeInt(hardKeyboardHidden);
1970         dest.writeInt(navigation);
1971         dest.writeInt(navigationHidden);
1972         dest.writeInt(orientation);
1973         dest.writeInt(screenLayout);
1974         dest.writeInt(colorMode);
1975         dest.writeInt(uiMode);
1976         dest.writeInt(screenWidthDp);
1977         dest.writeInt(screenHeightDp);
1978         dest.writeInt(smallestScreenWidthDp);
1979         dest.writeInt(densityDpi);
1980         dest.writeInt(compatScreenWidthDp);
1981         dest.writeInt(compatScreenHeightDp);
1982         dest.writeInt(compatSmallestScreenWidthDp);
1983         windowConfiguration.writeToParcel(dest, flags);
1984         dest.writeInt(assetsSeq);
1985         dest.writeInt(seq);
1986         dest.writeInt(fontWeightAdjustment);
1987     }
1988 
readFromParcel(Parcel source)1989     public void readFromParcel(Parcel source) {
1990         fontScale = source.readFloat();
1991         mcc = source.readInt();
1992         mnc = source.readInt();
1993 
1994         mLocaleList = source.readTypedObject(LocaleList.CREATOR);
1995         locale = mLocaleList.get(0);
1996 
1997         userSetLocale = (source.readInt()==1);
1998         touchscreen = source.readInt();
1999         keyboard = source.readInt();
2000         keyboardHidden = source.readInt();
2001         hardKeyboardHidden = source.readInt();
2002         navigation = source.readInt();
2003         navigationHidden = source.readInt();
2004         orientation = source.readInt();
2005         screenLayout = source.readInt();
2006         colorMode = source.readInt();
2007         uiMode = source.readInt();
2008         screenWidthDp = source.readInt();
2009         screenHeightDp = source.readInt();
2010         smallestScreenWidthDp = source.readInt();
2011         densityDpi = source.readInt();
2012         compatScreenWidthDp = source.readInt();
2013         compatScreenHeightDp = source.readInt();
2014         compatSmallestScreenWidthDp = source.readInt();
2015         windowConfiguration.readFromParcel(source);
2016         assetsSeq = source.readInt();
2017         seq = source.readInt();
2018         fontWeightAdjustment = source.readInt();
2019     }
2020 
2021     public static final @android.annotation.NonNull Parcelable.Creator<Configuration> CREATOR
2022             = new Parcelable.Creator<Configuration>() {
2023         public Configuration createFromParcel(Parcel source) {
2024             return new Configuration(source);
2025         }
2026 
2027         public Configuration[] newArray(int size) {
2028             return new Configuration[size];
2029         }
2030     };
2031 
2032     /**
2033      * Construct this Configuration object, reading from the Parcel.
2034      */
Configuration(Parcel source)2035     private Configuration(Parcel source) {
2036         readFromParcel(source);
2037     }
2038 
2039 
2040     /**
2041      * Retuns whether the configuration is in night mode
2042      * @return true if night mode is active and false otherwise
2043      */
isNightModeActive()2044     public boolean isNightModeActive() {
2045         return (uiMode & UI_MODE_NIGHT_MASK) == UI_MODE_NIGHT_YES;
2046     }
2047 
compareTo(Configuration that)2048     public int compareTo(Configuration that) {
2049         int n;
2050         float a = this.fontScale;
2051         float b = that.fontScale;
2052         if (a < b) return -1;
2053         if (a > b) return 1;
2054         n = this.mcc - that.mcc;
2055         if (n != 0) return n;
2056         n = this.mnc - that.mnc;
2057         if (n != 0) return n;
2058 
2059         fixUpLocaleList();
2060         that.fixUpLocaleList();
2061         // for backward compatibility, we consider an empty locale list to be greater
2062         // than any non-empty locale list.
2063         if (this.mLocaleList.isEmpty()) {
2064             if (!that.mLocaleList.isEmpty()) return 1;
2065         } else if (that.mLocaleList.isEmpty()) {
2066             return -1;
2067         } else {
2068             final int minSize = Math.min(this.mLocaleList.size(), that.mLocaleList.size());
2069             for (int i = 0; i < minSize; ++i) {
2070                 final Locale thisLocale = this.mLocaleList.get(i);
2071                 final Locale thatLocale = that.mLocaleList.get(i);
2072                 n = thisLocale.getLanguage().compareTo(thatLocale.getLanguage());
2073                 if (n != 0) return n;
2074                 n = thisLocale.getCountry().compareTo(thatLocale.getCountry());
2075                 if (n != 0) return n;
2076                 n = thisLocale.getVariant().compareTo(thatLocale.getVariant());
2077                 if (n != 0) return n;
2078                 n = thisLocale.toLanguageTag().compareTo(thatLocale.toLanguageTag());
2079                 if (n != 0) return n;
2080             }
2081             n = this.mLocaleList.size() - that.mLocaleList.size();
2082             if (n != 0) return n;
2083         }
2084 
2085         n = this.touchscreen - that.touchscreen;
2086         if (n != 0) return n;
2087         n = this.keyboard - that.keyboard;
2088         if (n != 0) return n;
2089         n = this.keyboardHidden - that.keyboardHidden;
2090         if (n != 0) return n;
2091         n = this.hardKeyboardHidden - that.hardKeyboardHidden;
2092         if (n != 0) return n;
2093         n = this.navigation - that.navigation;
2094         if (n != 0) return n;
2095         n = this.navigationHidden - that.navigationHidden;
2096         if (n != 0) return n;
2097         n = this.orientation - that.orientation;
2098         if (n != 0) return n;
2099         n = this.colorMode - that.colorMode;
2100         if (n != 0) return n;
2101         n = this.screenLayout - that.screenLayout;
2102         if (n != 0) return n;
2103         n = this.uiMode - that.uiMode;
2104         if (n != 0) return n;
2105         n = this.screenWidthDp - that.screenWidthDp;
2106         if (n != 0) return n;
2107         n = this.screenHeightDp - that.screenHeightDp;
2108         if (n != 0) return n;
2109         n = this.smallestScreenWidthDp - that.smallestScreenWidthDp;
2110         if (n != 0) return n;
2111         n = this.densityDpi - that.densityDpi;
2112         if (n != 0) return n;
2113         n = this.assetsSeq - that.assetsSeq;
2114         if (n != 0) return n;
2115         n = windowConfiguration.compareTo(that.windowConfiguration);
2116         if (n != 0) return n;
2117         n = this.fontWeightAdjustment - that.fontWeightAdjustment;
2118         if (n != 0) return n;
2119 
2120         // if (n != 0) return n;
2121         return n;
2122     }
2123 
equals(Configuration that)2124     public boolean equals(Configuration that) {
2125         if (that == null) return false;
2126         if (that == this) return true;
2127         return this.compareTo(that) == 0;
2128     }
2129 
equals(@ullable Object that)2130     public boolean equals(@Nullable Object that) {
2131         try {
2132             return equals((Configuration)that);
2133         } catch (ClassCastException e) {
2134         }
2135         return false;
2136     }
2137 
hashCode()2138     public int hashCode() {
2139         int result = 17;
2140         result = 31 * result + Float.floatToIntBits(fontScale);
2141         result = 31 * result + mcc;
2142         result = 31 * result + mnc;
2143         result = 31 * result + mLocaleList.hashCode();
2144         result = 31 * result + touchscreen;
2145         result = 31 * result + keyboard;
2146         result = 31 * result + keyboardHidden;
2147         result = 31 * result + hardKeyboardHidden;
2148         result = 31 * result + navigation;
2149         result = 31 * result + navigationHidden;
2150         result = 31 * result + orientation;
2151         result = 31 * result + screenLayout;
2152         result = 31 * result + colorMode;
2153         result = 31 * result + uiMode;
2154         result = 31 * result + screenWidthDp;
2155         result = 31 * result + screenHeightDp;
2156         result = 31 * result + smallestScreenWidthDp;
2157         result = 31 * result + densityDpi;
2158         result = 31 * result + assetsSeq;
2159         result = 31 * result + fontWeightAdjustment;
2160         return result;
2161     }
2162 
2163     /**
2164      * Get the locale list. This is the preferred way for getting the locales (instead of using
2165      * the direct accessor to {@link #locale}, which would only provide the primary locale).
2166      *
2167      * @return The locale list.
2168      */
getLocales()2169     public @NonNull LocaleList getLocales() {
2170         fixUpLocaleList();
2171         return mLocaleList;
2172     }
2173 
2174     /**
2175      * Set the locale list. This is the preferred way for setting up the locales (instead of using
2176      * the direct accessor or {@link #setLocale(Locale)}). This will also set the layout direction
2177      * according to the first locale in the list.
2178      *
2179      * Note that the layout direction will always come from the first locale in the locale list,
2180      * even if the locale is not supported by the resources (the resources may only support
2181      * another locale further down the list which has a different direction).
2182      *
2183      * @param locales The locale list. If null, an empty LocaleList will be assigned.
2184      */
setLocales(@ullable LocaleList locales)2185     public void setLocales(@Nullable LocaleList locales) {
2186         mLocaleList = locales == null ? LocaleList.getEmptyLocaleList() : locales;
2187         locale = mLocaleList.get(0);
2188         setLayoutDirection(locale);
2189     }
2190 
2191     /**
2192      * Set the locale list to a list of just one locale. This will also set the layout direction
2193      * according to the locale.
2194      *
2195      * Note that after this is run, calling <code>.equals()</code> on the input locale and the
2196      * {@link #locale} attribute would return <code>true</code> if they are not null, but there is
2197      * no guarantee that they would be the same object.
2198      *
2199      * See also the note about layout direction in {@link #setLocales(LocaleList)}.
2200      *
2201      * @param loc The locale. Can be null.
2202      */
setLocale(@ullable Locale loc)2203     public void setLocale(@Nullable Locale loc) {
2204         setLocales(loc == null ? LocaleList.getEmptyLocaleList() : new LocaleList(loc));
2205     }
2206 
2207     /**
2208      * @hide
2209      *
2210      * Clears the locale without changing layout direction.
2211      */
clearLocales()2212     public void clearLocales() {
2213         mLocaleList = LocaleList.getEmptyLocaleList();
2214         locale = null;
2215     }
2216 
2217     /**
2218      * Return the layout direction. Will be either {@link View#LAYOUT_DIRECTION_LTR} or
2219      * {@link View#LAYOUT_DIRECTION_RTL}.
2220      *
2221      * @return Returns {@link View#LAYOUT_DIRECTION_RTL} if the configuration
2222      * is {@link #SCREENLAYOUT_LAYOUTDIR_RTL}, otherwise {@link View#LAYOUT_DIRECTION_LTR}.
2223      */
getLayoutDirection()2224     public int getLayoutDirection() {
2225         return (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK) == SCREENLAYOUT_LAYOUTDIR_RTL
2226                 ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
2227     }
2228 
2229     /**
2230      * Set the layout direction from a Locale.
2231      *
2232      * @param loc The Locale. If null will set the layout direction to
2233      * {@link View#LAYOUT_DIRECTION_LTR}. If not null will set it to the layout direction
2234      * corresponding to the Locale.
2235      *
2236      * @see View#LAYOUT_DIRECTION_LTR
2237      * @see View#LAYOUT_DIRECTION_RTL
2238      */
setLayoutDirection(Locale loc)2239     public void setLayoutDirection(Locale loc) {
2240         // There is a "1" difference between the configuration values for
2241         // layout direction and View constants for layout direction, just add "1".
2242         final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(loc);
2243         screenLayout = (screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK)|
2244                 (layoutDirection << SCREENLAYOUT_LAYOUTDIR_SHIFT);
2245     }
2246 
getScreenLayoutNoDirection(int screenLayout)2247     private static int getScreenLayoutNoDirection(int screenLayout) {
2248         return screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK;
2249     }
2250 
2251     /**
2252      * Return whether the screen has a round shape. Apps may choose to change styling based
2253      * on this property, such as the alignment or layout of text or informational icons.
2254      *
2255      * @return true if the screen is rounded, false otherwise
2256      */
isScreenRound()2257     public boolean isScreenRound() {
2258         return (screenLayout & SCREENLAYOUT_ROUND_MASK) == SCREENLAYOUT_ROUND_YES;
2259     }
2260 
2261     /**
2262      * Return whether the screen has a wide color gamut and wide color gamut rendering
2263      * is supported by this device.
2264      *
2265      * When true, it implies the screen is colorspace aware but not
2266      * necessarily color-managed. The final colors may still be changed by the
2267      * screen depending on user settings.
2268      *
2269      * @return true if the screen has a wide color gamut and wide color gamut rendering
2270      * is supported, false otherwise
2271      */
isScreenWideColorGamut()2272     public boolean isScreenWideColorGamut() {
2273         return (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) == COLOR_MODE_WIDE_COLOR_GAMUT_YES;
2274     }
2275 
2276     /**
2277      * Return whether the screen has a high dynamic range.
2278      *
2279      * @return true if the screen has a high dynamic range, false otherwise
2280      */
isScreenHdr()2281     public boolean isScreenHdr() {
2282         return (colorMode & COLOR_MODE_HDR_MASK) == COLOR_MODE_HDR_YES;
2283     }
2284 
2285     /**
2286      *
2287      * @hide
2288      */
localesToResourceQualifier(LocaleList locs)2289     public static String localesToResourceQualifier(LocaleList locs) {
2290         final StringBuilder sb = new StringBuilder();
2291         for (int i = 0; i < locs.size(); i++) {
2292             final Locale loc = locs.get(i);
2293             final int l = loc.getLanguage().length();
2294             if (l == 0) {
2295                 continue;
2296             }
2297             final int s = loc.getScript().length();
2298             final int c = loc.getCountry().length();
2299             final int v = loc.getVariant().length();
2300             // We ignore locale extensions, since they are not supported by AAPT
2301 
2302             if (sb.length() != 0) {
2303                 sb.append(",");
2304             }
2305             if (l == 2 && s == 0 && (c == 0 || c == 2) && v == 0) {
2306                 // Traditional locale format: xx or xx-rYY
2307                 sb.append(loc.getLanguage());
2308                 if (c == 2) {
2309                     sb.append("-r").append(loc.getCountry());
2310                 }
2311             } else {
2312                 sb.append("b+");
2313                 sb.append(loc.getLanguage());
2314                 if (s != 0) {
2315                     sb.append("+");
2316                     sb.append(loc.getScript());
2317                 }
2318                 if (c != 0) {
2319                     sb.append("+");
2320                     sb.append(loc.getCountry());
2321                 }
2322                 if (v != 0) {
2323                     sb.append("+");
2324                     sb.append(loc.getVariant());
2325                 }
2326             }
2327         }
2328         return sb.toString();
2329     }
2330 
2331 
2332     /**
2333      * Returns a string representation of the configuration that can be parsed
2334      * by build tools (like AAPT), without display metrics included
2335      *
2336      * @hide
2337      */
2338     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
resourceQualifierString(Configuration config)2339     public static String resourceQualifierString(Configuration config) {
2340         return resourceQualifierString(config, null);
2341     }
2342 
2343     /**
2344      * Returns a string representation of the configuration that can be parsed
2345      * by build tools (like AAPT).
2346      *
2347      * @hide
2348      */
resourceQualifierString(Configuration config, DisplayMetrics metrics)2349     public static String resourceQualifierString(Configuration config, DisplayMetrics metrics) {
2350         ArrayList<String> parts = new ArrayList<String>();
2351 
2352         if (config.mcc != 0) {
2353             parts.add("mcc" + config.mcc);
2354             if (config.mnc != 0) {
2355                 parts.add("mnc" + config.mnc);
2356             }
2357         }
2358 
2359         if (!config.mLocaleList.isEmpty()) {
2360             final String resourceQualifier = localesToResourceQualifier(config.mLocaleList);
2361             if (!resourceQualifier.isEmpty()) {
2362                 parts.add(resourceQualifier);
2363             }
2364         }
2365 
2366         switch (config.screenLayout & Configuration.SCREENLAYOUT_LAYOUTDIR_MASK) {
2367             case Configuration.SCREENLAYOUT_LAYOUTDIR_LTR:
2368                 parts.add("ldltr");
2369                 break;
2370             case Configuration.SCREENLAYOUT_LAYOUTDIR_RTL:
2371                 parts.add("ldrtl");
2372                 break;
2373             default:
2374                 break;
2375         }
2376 
2377         if (config.smallestScreenWidthDp != 0) {
2378             parts.add("sw" + config.smallestScreenWidthDp + "dp");
2379         }
2380 
2381         if (config.screenWidthDp != 0) {
2382             parts.add("w" + config.screenWidthDp + "dp");
2383         }
2384 
2385         if (config.screenHeightDp != 0) {
2386             parts.add("h" + config.screenHeightDp + "dp");
2387         }
2388 
2389         switch (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) {
2390             case Configuration.SCREENLAYOUT_SIZE_SMALL:
2391                 parts.add("small");
2392                 break;
2393             case Configuration.SCREENLAYOUT_SIZE_NORMAL:
2394                 parts.add("normal");
2395                 break;
2396             case Configuration.SCREENLAYOUT_SIZE_LARGE:
2397                 parts.add("large");
2398                 break;
2399             case Configuration.SCREENLAYOUT_SIZE_XLARGE:
2400                 parts.add("xlarge");
2401                 break;
2402             default:
2403                 break;
2404         }
2405 
2406         switch (config.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK) {
2407             case Configuration.SCREENLAYOUT_LONG_YES:
2408                 parts.add("long");
2409                 break;
2410             case Configuration.SCREENLAYOUT_LONG_NO:
2411                 parts.add("notlong");
2412                 break;
2413             default:
2414                 break;
2415         }
2416 
2417         switch (config.screenLayout & Configuration.SCREENLAYOUT_ROUND_MASK) {
2418             case Configuration.SCREENLAYOUT_ROUND_YES:
2419                 parts.add("round");
2420                 break;
2421             case Configuration.SCREENLAYOUT_ROUND_NO:
2422                 parts.add("notround");
2423                 break;
2424             default:
2425                 break;
2426         }
2427 
2428         switch (config.colorMode & Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_MASK) {
2429             case Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_YES:
2430                 parts.add("widecg");
2431                 break;
2432             case Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_NO:
2433                 parts.add("nowidecg");
2434                 break;
2435             default:
2436                 break;
2437         }
2438 
2439         switch (config.colorMode & Configuration.COLOR_MODE_HDR_MASK) {
2440             case Configuration.COLOR_MODE_HDR_YES:
2441                 parts.add("highdr");
2442                 break;
2443             case Configuration.COLOR_MODE_HDR_NO:
2444                 parts.add("lowdr");
2445                 break;
2446             default:
2447                 break;
2448         }
2449 
2450         switch (config.orientation) {
2451             case Configuration.ORIENTATION_LANDSCAPE:
2452                 parts.add("land");
2453                 break;
2454             case Configuration.ORIENTATION_PORTRAIT:
2455                 parts.add("port");
2456                 break;
2457             default:
2458                 break;
2459         }
2460 
2461         switch (config.uiMode & Configuration.UI_MODE_TYPE_MASK) {
2462             case Configuration.UI_MODE_TYPE_APPLIANCE:
2463                 parts.add("appliance");
2464                 break;
2465             case Configuration.UI_MODE_TYPE_DESK:
2466                 parts.add("desk");
2467                 break;
2468             case Configuration.UI_MODE_TYPE_TELEVISION:
2469                 parts.add("television");
2470                 break;
2471             case Configuration.UI_MODE_TYPE_CAR:
2472                 parts.add("car");
2473                 break;
2474             case Configuration.UI_MODE_TYPE_WATCH:
2475                 parts.add("watch");
2476                 break;
2477             case Configuration.UI_MODE_TYPE_VR_HEADSET:
2478                 parts.add("vrheadset");
2479                 break;
2480             default:
2481                 break;
2482         }
2483 
2484         switch (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) {
2485             case Configuration.UI_MODE_NIGHT_YES:
2486                 parts.add("night");
2487                 break;
2488             case Configuration.UI_MODE_NIGHT_NO:
2489                 parts.add("notnight");
2490                 break;
2491             default:
2492                 break;
2493         }
2494 
2495         switch (config.densityDpi) {
2496             case DENSITY_DPI_UNDEFINED:
2497                 break;
2498             case 120:
2499                 parts.add("ldpi");
2500                 break;
2501             case 160:
2502                 parts.add("mdpi");
2503                 break;
2504             case 213:
2505                 parts.add("tvdpi");
2506                 break;
2507             case 240:
2508                 parts.add("hdpi");
2509                 break;
2510             case 320:
2511                 parts.add("xhdpi");
2512                 break;
2513             case 480:
2514                 parts.add("xxhdpi");
2515                 break;
2516             case 640:
2517                 parts.add("xxxhdpi");
2518                 break;
2519             case DENSITY_DPI_ANY:
2520                 parts.add("anydpi");
2521                 break;
2522             case DENSITY_DPI_NONE:
2523                 parts.add("nodpi");
2524                 break;
2525             default:
2526                 parts.add(config.densityDpi + "dpi");
2527                 break;
2528         }
2529 
2530         switch (config.touchscreen) {
2531             case Configuration.TOUCHSCREEN_NOTOUCH:
2532                 parts.add("notouch");
2533                 break;
2534             case Configuration.TOUCHSCREEN_FINGER:
2535                 parts.add("finger");
2536                 break;
2537             default:
2538                 break;
2539         }
2540 
2541         switch (config.keyboardHidden) {
2542             case Configuration.KEYBOARDHIDDEN_NO:
2543                 parts.add("keysexposed");
2544                 break;
2545             case Configuration.KEYBOARDHIDDEN_YES:
2546                 parts.add("keyshidden");
2547                 break;
2548             case Configuration.KEYBOARDHIDDEN_SOFT:
2549                 parts.add("keyssoft");
2550                 break;
2551             default:
2552                 break;
2553         }
2554 
2555         switch (config.keyboard) {
2556             case Configuration.KEYBOARD_NOKEYS:
2557                 parts.add("nokeys");
2558                 break;
2559             case Configuration.KEYBOARD_QWERTY:
2560                 parts.add("qwerty");
2561                 break;
2562             case Configuration.KEYBOARD_12KEY:
2563                 parts.add("12key");
2564                 break;
2565             default:
2566                 break;
2567         }
2568 
2569         switch (config.navigationHidden) {
2570             case Configuration.NAVIGATIONHIDDEN_NO:
2571                 parts.add("navexposed");
2572                 break;
2573             case Configuration.NAVIGATIONHIDDEN_YES:
2574                 parts.add("navhidden");
2575                 break;
2576             default:
2577                 break;
2578         }
2579 
2580         switch (config.navigation) {
2581             case Configuration.NAVIGATION_NONAV:
2582                 parts.add("nonav");
2583                 break;
2584             case Configuration.NAVIGATION_DPAD:
2585                 parts.add("dpad");
2586                 break;
2587             case Configuration.NAVIGATION_TRACKBALL:
2588                 parts.add("trackball");
2589                 break;
2590             case Configuration.NAVIGATION_WHEEL:
2591                 parts.add("wheel");
2592                 break;
2593             default:
2594                 break;
2595         }
2596 
2597         if (metrics != null) {
2598             final int width, height;
2599             if (metrics.widthPixels >= metrics.heightPixels) {
2600                 width = metrics.widthPixels;
2601                 height = metrics.heightPixels;
2602             } else {
2603                 //noinspection SuspiciousNameCombination
2604                 width = metrics.heightPixels;
2605                 //noinspection SuspiciousNameCombination
2606                 height = metrics.widthPixels;
2607             }
2608             parts.add(width + "x" + height);
2609         }
2610 
2611         parts.add("v" + Build.VERSION.RESOURCES_SDK_INT);
2612         return TextUtils.join("-", parts);
2613     }
2614 
2615     /**
2616      * Generate a delta Configuration between <code>base</code> and <code>change</code>. The
2617      * resulting delta can be used with {@link #updateFrom(Configuration)}.
2618      * <p />
2619      * Caveat: If the any of the Configuration's members becomes undefined, then
2620      * {@link #updateFrom(Configuration)} will treat it as a no-op and not update that member.
2621      *
2622      * This is fine for device configurations as no member is ever undefined.
2623      * {@hide}
2624      */
2625     @UnsupportedAppUsage
generateDelta(Configuration base, Configuration change)2626     public static Configuration generateDelta(Configuration base, Configuration change) {
2627         final Configuration delta = new Configuration();
2628         if (base.fontScale != change.fontScale) {
2629             delta.fontScale = change.fontScale;
2630         }
2631 
2632         if (base.mcc != change.mcc) {
2633             delta.mcc = change.mcc;
2634         }
2635 
2636         if (base.mnc != change.mnc) {
2637             delta.mnc = change.mnc;
2638         }
2639 
2640         base.fixUpLocaleList();
2641         change.fixUpLocaleList();
2642         if (!base.mLocaleList.equals(change.mLocaleList))  {
2643             delta.mLocaleList = change.mLocaleList;
2644             delta.locale = change.locale;
2645         }
2646 
2647         if (base.touchscreen != change.touchscreen) {
2648             delta.touchscreen = change.touchscreen;
2649         }
2650 
2651         if (base.keyboard != change.keyboard) {
2652             delta.keyboard = change.keyboard;
2653         }
2654 
2655         if (base.keyboardHidden != change.keyboardHidden) {
2656             delta.keyboardHidden = change.keyboardHidden;
2657         }
2658 
2659         if (base.navigation != change.navigation) {
2660             delta.navigation = change.navigation;
2661         }
2662 
2663         if (base.navigationHidden != change.navigationHidden) {
2664             delta.navigationHidden = change.navigationHidden;
2665         }
2666 
2667         if (base.orientation != change.orientation) {
2668             delta.orientation = change.orientation;
2669         }
2670 
2671         if ((base.screenLayout & SCREENLAYOUT_SIZE_MASK) !=
2672                 (change.screenLayout & SCREENLAYOUT_SIZE_MASK)) {
2673             delta.screenLayout |= change.screenLayout & SCREENLAYOUT_SIZE_MASK;
2674         }
2675 
2676         if ((base.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK) !=
2677                 (change.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) {
2678             delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
2679         }
2680 
2681         if ((base.screenLayout & SCREENLAYOUT_LONG_MASK) !=
2682                 (change.screenLayout & SCREENLAYOUT_LONG_MASK)) {
2683             delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LONG_MASK;
2684         }
2685 
2686         if ((base.screenLayout & SCREENLAYOUT_ROUND_MASK) !=
2687                 (change.screenLayout & SCREENLAYOUT_ROUND_MASK)) {
2688             delta.screenLayout |= change.screenLayout & SCREENLAYOUT_ROUND_MASK;
2689         }
2690 
2691         if ((base.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) !=
2692                 (change.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) {
2693             delta.colorMode |= change.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK;
2694         }
2695 
2696         if ((base.colorMode & COLOR_MODE_HDR_MASK) !=
2697                 (change.colorMode & COLOR_MODE_HDR_MASK)) {
2698             delta.colorMode |= change.colorMode & COLOR_MODE_HDR_MASK;
2699         }
2700 
2701         if ((base.uiMode & UI_MODE_TYPE_MASK) != (change.uiMode & UI_MODE_TYPE_MASK)) {
2702             delta.uiMode |= change.uiMode & UI_MODE_TYPE_MASK;
2703         }
2704 
2705         if ((base.uiMode & UI_MODE_NIGHT_MASK) != (change.uiMode & UI_MODE_NIGHT_MASK)) {
2706             delta.uiMode |= change.uiMode & UI_MODE_NIGHT_MASK;
2707         }
2708 
2709         if (base.screenWidthDp != change.screenWidthDp) {
2710             delta.screenWidthDp = change.screenWidthDp;
2711         }
2712 
2713         if (base.screenHeightDp != change.screenHeightDp) {
2714             delta.screenHeightDp = change.screenHeightDp;
2715         }
2716 
2717         if (base.smallestScreenWidthDp != change.smallestScreenWidthDp) {
2718             delta.smallestScreenWidthDp = change.smallestScreenWidthDp;
2719         }
2720 
2721         if (base.densityDpi != change.densityDpi) {
2722             delta.densityDpi = change.densityDpi;
2723         }
2724 
2725         if (base.assetsSeq != change.assetsSeq) {
2726             delta.assetsSeq = change.assetsSeq;
2727         }
2728 
2729         if (!base.windowConfiguration.equals(change.windowConfiguration)) {
2730             delta.windowConfiguration.setTo(change.windowConfiguration);
2731         }
2732 
2733         if (base.fontWeightAdjustment != change.fontWeightAdjustment) {
2734             delta.fontWeightAdjustment = change.fontWeightAdjustment;
2735         }
2736         return delta;
2737     }
2738 
2739     private static final String XML_ATTR_FONT_SCALE = "fs";
2740     private static final String XML_ATTR_MCC = "mcc";
2741     private static final String XML_ATTR_MNC = "mnc";
2742     private static final String XML_ATTR_LOCALES = "locales";
2743     private static final String XML_ATTR_TOUCHSCREEN = "touch";
2744     private static final String XML_ATTR_KEYBOARD = "key";
2745     private static final String XML_ATTR_KEYBOARD_HIDDEN = "keyHid";
2746     private static final String XML_ATTR_HARD_KEYBOARD_HIDDEN = "hardKeyHid";
2747     private static final String XML_ATTR_NAVIGATION = "nav";
2748     private static final String XML_ATTR_NAVIGATION_HIDDEN = "navHid";
2749     private static final String XML_ATTR_ORIENTATION = "ori";
2750     private static final String XML_ATTR_ROTATION = "rot";
2751     private static final String XML_ATTR_SCREEN_LAYOUT = "scrLay";
2752     private static final String XML_ATTR_COLOR_MODE = "clrMod";
2753     private static final String XML_ATTR_UI_MODE = "ui";
2754     private static final String XML_ATTR_SCREEN_WIDTH = "width";
2755     private static final String XML_ATTR_SCREEN_HEIGHT = "height";
2756     private static final String XML_ATTR_SMALLEST_WIDTH = "sw";
2757     private static final String XML_ATTR_DENSITY = "density";
2758     private static final String XML_ATTR_APP_BOUNDS = "app_bounds";
2759     private static final String XML_ATTR_FONT_WEIGHT_ADJUSTMENT = "fontWeightAdjustment";
2760 
2761     /**
2762      * Reads the attributes corresponding to Configuration member fields from the Xml parser.
2763      * The parser is expected to be on a tag which has Configuration attributes.
2764      *
2765      * @param parser The Xml parser from which to read attributes.
2766      * @param configOut The Configuration to populate from the Xml attributes.
2767      * {@hide}
2768      */
readXmlAttrs(XmlPullParser parser, Configuration configOut)2769     public static void readXmlAttrs(XmlPullParser parser, Configuration configOut)
2770             throws XmlPullParserException, IOException {
2771         configOut.fontScale = Float.intBitsToFloat(
2772                 XmlUtils.readIntAttribute(parser, XML_ATTR_FONT_SCALE, 0));
2773         configOut.mcc = XmlUtils.readIntAttribute(parser, XML_ATTR_MCC, 0);
2774         configOut.mnc = XmlUtils.readIntAttribute(parser, XML_ATTR_MNC, 0);
2775 
2776         final String localesStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALES);
2777         configOut.mLocaleList = LocaleList.forLanguageTags(localesStr);
2778         configOut.locale = configOut.mLocaleList.get(0);
2779 
2780         configOut.touchscreen = XmlUtils.readIntAttribute(parser, XML_ATTR_TOUCHSCREEN,
2781                 TOUCHSCREEN_UNDEFINED);
2782         configOut.keyboard = XmlUtils.readIntAttribute(parser, XML_ATTR_KEYBOARD,
2783                 KEYBOARD_UNDEFINED);
2784         configOut.keyboardHidden = XmlUtils.readIntAttribute(parser, XML_ATTR_KEYBOARD_HIDDEN,
2785                 KEYBOARDHIDDEN_UNDEFINED);
2786         configOut.hardKeyboardHidden =
2787                 XmlUtils.readIntAttribute(parser, XML_ATTR_HARD_KEYBOARD_HIDDEN,
2788                         HARDKEYBOARDHIDDEN_UNDEFINED);
2789         configOut.navigation = XmlUtils.readIntAttribute(parser, XML_ATTR_NAVIGATION,
2790                 NAVIGATION_UNDEFINED);
2791         configOut.navigationHidden = XmlUtils.readIntAttribute(parser, XML_ATTR_NAVIGATION_HIDDEN,
2792                 NAVIGATIONHIDDEN_UNDEFINED);
2793         configOut.orientation = XmlUtils.readIntAttribute(parser, XML_ATTR_ORIENTATION,
2794                 ORIENTATION_UNDEFINED);
2795         configOut.screenLayout = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_LAYOUT,
2796                 SCREENLAYOUT_UNDEFINED);
2797         configOut.colorMode = XmlUtils.readIntAttribute(parser, XML_ATTR_COLOR_MODE,
2798                 COLOR_MODE_UNDEFINED);
2799         configOut.uiMode = XmlUtils.readIntAttribute(parser, XML_ATTR_UI_MODE, 0);
2800         configOut.screenWidthDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_WIDTH,
2801                 SCREEN_WIDTH_DP_UNDEFINED);
2802         configOut.screenHeightDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_HEIGHT,
2803                 SCREEN_HEIGHT_DP_UNDEFINED);
2804         configOut.smallestScreenWidthDp =
2805                 XmlUtils.readIntAttribute(parser, XML_ATTR_SMALLEST_WIDTH,
2806                         SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
2807         configOut.densityDpi = XmlUtils.readIntAttribute(parser, XML_ATTR_DENSITY,
2808                 DENSITY_DPI_UNDEFINED);
2809         configOut.fontWeightAdjustment = XmlUtils.readIntAttribute(parser,
2810                 XML_ATTR_FONT_WEIGHT_ADJUSTMENT, FONT_WEIGHT_ADJUSTMENT_UNDEFINED);
2811 
2812         // For persistence, we don't care about assetsSeq and WindowConfiguration, so do not read it
2813         // out.
2814     }
2815 }
2816