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