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