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