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