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