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
17package android.content.res;
18
19import android.graphics.Point;
20import android.graphics.Rect;
21import android.util.DisplayMetrics;
22import android.view.Display;
23import android.view.DisplayInfo;
24import com.android.internal.util.XmlUtils;
25
26import org.xmlpull.v1.XmlPullParser;
27import org.xmlpull.v1.XmlPullParserException;
28import org.xmlpull.v1.XmlSerializer;
29
30import android.annotation.IntDef;
31import android.annotation.NonNull;
32import android.annotation.Nullable;
33import android.content.pm.ActivityInfo;
34import android.content.pm.ActivityInfo.Config;
35import android.os.Build;
36import android.os.LocaleList;
37import android.os.Parcel;
38import android.os.Parcelable;
39import android.text.TextUtils;
40import android.view.View;
41
42import java.io.IOException;
43import java.lang.annotation.Retention;
44import java.lang.annotation.RetentionPolicy;
45import java.util.ArrayList;
46import 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 */
58public 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 */
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 */
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 */
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     */
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     */
850    public Configuration() {
851        unset();
852    }
853
854    /**
855     * Makes a deep copy suitable for modification.
856     */
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. */
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     */
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
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     */
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     */
1096    public void unset() {
1097        setToDefaults();
1098        fontScale = 0;
1099    }
1100
1101    /** {@hide} */
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     */
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     */
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     */
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     */
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     */
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     */
1489    public int describeContents() {
1490        return 0;
1491    }
1492
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
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     */
1583    private Configuration(Parcel source) {
1584        readFromParcel(source);
1585    }
1586
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
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
1663    public boolean equals(Object that) {
1664        try {
1665            return equals((Configuration)that);
1666        } catch (ClassCastException e) {
1667        }
1668        return false;
1669    }
1670
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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
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     */
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     */
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     */
1834    public boolean isScreenHdr() {
1835        return (colorMode & COLOR_MODE_HDR_MASK) == COLOR_MODE_HDR_YES;
1836    }
1837
1838    /**
1839     *
1840     * @hide
1841     */
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     */
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     */
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     */
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     */
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