Home | History | Annotate | Download | only in res
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.content.res;
     18 
     19 import android.graphics.Point;
     20 import android.graphics.Rect;
     21 import android.util.DisplayMetrics;
     22 import android.view.Display;
     23 import android.view.DisplayInfo;
     24 import com.android.internal.util.XmlUtils;
     25 
     26 import org.xmlpull.v1.XmlPullParser;
     27 import org.xmlpull.v1.XmlPullParserException;
     28 import org.xmlpull.v1.XmlSerializer;
     29 
     30 import android.annotation.IntDef;
     31 import android.annotation.NonNull;
     32 import android.annotation.Nullable;
     33 import android.content.pm.ActivityInfo;
     34 import android.content.pm.ActivityInfo.Config;
     35 import android.os.Build;
     36 import android.os.LocaleList;
     37 import android.os.Parcel;
     38 import android.os.Parcelable;
     39 import android.text.TextUtils;
     40 import android.view.View;
     41 
     42 import java.io.IOException;
     43 import java.lang.annotation.Retention;
     44 import java.lang.annotation.RetentionPolicy;
     45 import java.util.ArrayList;
     46 import java.util.Locale;
     47 
     48 /**
     49  * This class describes all device configuration information that can
     50  * impact the resources the application retrieves.  This includes both
     51  * user-specified configuration options (locale list and scaling) as well
     52  * as device configurations (such as input modes, screen size and screen orientation).
     53  * <p>You can acquire this object from {@link Resources}, using {@link
     54  * Resources#getConfiguration}. Thus, from an activity, you can get it by chaining the request
     55  * with {@link android.app.Activity#getResources}:</p>
     56  * <pre>Configuration config = getResources().getConfiguration();</pre>
     57  */
     58 public final class Configuration implements Parcelable, Comparable<Configuration> {
     59     /** @hide */
     60     public static final Configuration EMPTY = new Configuration();
     61 
     62     /**
     63      * Current user preference for the scaling factor for fonts, relative
     64      * to the base density scaling.
     65      */
     66     public float fontScale;
     67 
     68     /**
     69      * IMSI MCC (Mobile Country Code), corresponding to
     70      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mcc</a>
     71      * resource qualifier.  0 if undefined.
     72      */
     73     public int mcc;
     74 
     75     /**
     76      * IMSI MNC (Mobile Network Code), corresponding to
     77      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mnc</a>
     78      * resource qualifier.  0 if undefined. Note that the actual MNC may be 0; in order to check
     79      * for this use the {@link #MNC_ZERO} symbol.
     80      */
     81     public int mnc;
     82 
     83     /**
     84      * Constant used to to represent MNC (Mobile Network Code) zero.
     85      * 0 cannot be used, since it is used to represent an undefined MNC.
     86      */
     87     public static final int MNC_ZERO = 0xffff;
     88 
     89     /**
     90      * Current user preference for the locale, corresponding to
     91      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a>
     92      * resource qualifier.
     93      *
     94      * @deprecated Do not set or read this directly. Use {@link #getLocales()} and
     95      * {@link #setLocales(LocaleList)}. If only the primary locale is needed,
     96      * <code>getLocales().get(0)</code> is now the preferred accessor.
     97      */
     98     @Deprecated public Locale locale;
     99 
    100     private LocaleList mLocaleList;
    101 
    102     /**
    103      * Locale should persist on setting.  This is hidden because it is really
    104      * questionable whether this is the right way to expose the functionality.
    105      * @hide
    106      */
    107     public boolean userSetLocale;
    108 
    109 
    110     /** Constant for {@link #colorMode}: bits that encode whether the screen is wide gamut. */
    111     public static final int COLOR_MODE_WIDE_COLOR_GAMUT_MASK = 0x3;
    112     /**
    113      * Constant for {@link #colorMode}: a {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} value
    114      * indicating that it is unknown whether or not the screen is wide gamut.
    115      */
    116     public static final int COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED = 0x0;
    117     /**
    118      * Constant for {@link #colorMode}: a {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} value
    119      * indicating that the screen is not wide gamut.
    120      * <p>Corresponds to the <code>-nowidecg</code> resource qualifier.</p>
    121      */
    122     public static final int COLOR_MODE_WIDE_COLOR_GAMUT_NO = 0x1;
    123     /**
    124      * Constant for {@link #colorMode}: a {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} value
    125      * indicating that the screen is wide gamut.
    126      * <p>Corresponds to the <code>-widecg</code> resource qualifier.</p>
    127      */
    128     public static final int COLOR_MODE_WIDE_COLOR_GAMUT_YES = 0x2;
    129 
    130     /** Constant for {@link #colorMode}: bits that encode the dynamic range of the screen. */
    131     public static final int COLOR_MODE_HDR_MASK = 0xc;
    132     /** Constant for {@link #colorMode}: bits shift to get the screen dynamic range. */
    133     public static final int COLOR_MODE_HDR_SHIFT = 2;
    134     /**
    135      * Constant for {@link #colorMode}: a {@link #COLOR_MODE_HDR_MASK} value
    136      * indicating that it is unknown whether or not the screen is HDR.
    137      */
    138     public static final int COLOR_MODE_HDR_UNDEFINED = 0x0;
    139     /**
    140      * Constant for {@link #colorMode}: a {@link #COLOR_MODE_HDR_MASK} value
    141      * indicating that the screen is not HDR (low/standard dynamic range).
    142      * <p>Corresponds to the <code>-lowdr</code> resource qualifier.</p>
    143      */
    144     public static final int COLOR_MODE_HDR_NO = 0x1 << COLOR_MODE_HDR_SHIFT;
    145     /**
    146      * Constant for {@link #colorMode}: a {@link #COLOR_MODE_HDR_MASK} value
    147      * indicating that the screen is HDR (dynamic range).
    148      * <p>Corresponds to the <code>-highdr</code> resource qualifier.</p>
    149      */
    150     public static final int COLOR_MODE_HDR_YES = 0x2 << COLOR_MODE_HDR_SHIFT;
    151 
    152     /** Constant for {@link #colorMode}: a value indicating that the color mode is undefined */
    153     @SuppressWarnings("PointlessBitwiseExpression")
    154     public static final int COLOR_MODE_UNDEFINED = COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED |
    155             COLOR_MODE_HDR_UNDEFINED;
    156 
    157     /**
    158      * Bit mask of color capabilities of the screen. Currently there are two fields:
    159      * <p>The {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} bits define the color gamut of
    160      * the screen. They may be one of
    161      * {@link #COLOR_MODE_WIDE_COLOR_GAMUT_NO} or {@link #COLOR_MODE_WIDE_COLOR_GAMUT_YES}.</p>
    162      *
    163      * <p>The {@link #COLOR_MODE_HDR_MASK} defines the dynamic range of the screen. They may be
    164      * one of {@link #COLOR_MODE_HDR_NO} or {@link #COLOR_MODE_HDR_YES}.</p>
    165      *
    166      * <p>See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
    167      * Multiple Screens</a> for more information.</p>
    168      */
    169     public int colorMode;
    170 
    171     /** Constant for {@link #screenLayout}: bits that encode the size. */
    172     public static final int SCREENLAYOUT_SIZE_MASK = 0x0f;
    173     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
    174      * value indicating that no size has been set. */
    175     public static final int SCREENLAYOUT_SIZE_UNDEFINED = 0x00;
    176     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
    177      * value indicating the screen is at least approximately 320x426 dp units,
    178      * corresponds to the
    179      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">small</a>
    180      * resource qualifier.
    181      * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
    182      * Multiple Screens</a> for more information. */
    183     public static final int SCREENLAYOUT_SIZE_SMALL = 0x01;
    184     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
    185      * value indicating the screen is at least approximately 320x470 dp units,
    186      * corresponds to the
    187      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">normal</a>
    188      * resource qualifier.
    189      * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
    190      * Multiple Screens</a> for more information. */
    191     public static final int SCREENLAYOUT_SIZE_NORMAL = 0x02;
    192     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
    193      * value indicating the screen is at least approximately 480x640 dp units,
    194      * corresponds to the
    195      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">large</a>
    196      * resource qualifier.
    197      * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
    198      * Multiple Screens</a> for more information. */
    199     public static final int SCREENLAYOUT_SIZE_LARGE = 0x03;
    200     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
    201      * value indicating the screen is at least approximately 720x960 dp units,
    202      * corresponds to the
    203      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">xlarge</a>
    204      * resource qualifier.
    205      * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
    206      * Multiple Screens</a> for more information.*/
    207     public static final int SCREENLAYOUT_SIZE_XLARGE = 0x04;
    208 
    209     /** Constant for {@link #screenLayout}: bits that encode the aspect ratio. */
    210     public static final int SCREENLAYOUT_LONG_MASK = 0x30;
    211     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK}
    212      * value indicating that no size has been set. */
    213     public static final int SCREENLAYOUT_LONG_UNDEFINED = 0x00;
    214     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK}
    215      * value that corresponds to the
    216      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenAspectQualifier">notlong</a>
    217      * resource qualifier. */
    218     public static final int SCREENLAYOUT_LONG_NO = 0x10;
    219     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK}
    220      * value that corresponds to the
    221      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenAspectQualifier">long</a>
    222      * resource qualifier. */
    223     public static final int SCREENLAYOUT_LONG_YES = 0x20;
    224 
    225     /** Constant for {@link #screenLayout}: bits that encode the layout direction. */
    226     public static final int SCREENLAYOUT_LAYOUTDIR_MASK = 0xC0;
    227     /** Constant for {@link #screenLayout}: bits shift to get the layout direction. */
    228     public static final int SCREENLAYOUT_LAYOUTDIR_SHIFT = 6;
    229     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK}
    230      * value indicating that no layout dir has been set. */
    231     public static final int SCREENLAYOUT_LAYOUTDIR_UNDEFINED = 0x00;
    232     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK}
    233      * value indicating that a layout dir has been set to LTR. */
    234     public static final int SCREENLAYOUT_LAYOUTDIR_LTR = 0x01 << SCREENLAYOUT_LAYOUTDIR_SHIFT;
    235     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK}
    236      * value indicating that a layout dir has been set to RTL. */
    237     public static final int SCREENLAYOUT_LAYOUTDIR_RTL = 0x02 << SCREENLAYOUT_LAYOUTDIR_SHIFT;
    238 
    239     /** Constant for {@link #screenLayout}: bits that encode roundness of the screen. */
    240     public static final int SCREENLAYOUT_ROUND_MASK = 0x300;
    241     /** @hide Constant for {@link #screenLayout}: bit shift to get to screen roundness bits */
    242     public static final int SCREENLAYOUT_ROUND_SHIFT = 8;
    243     /**
    244      * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating
    245      * that it is unknown whether or not the screen has a round shape.
    246      */
    247     public static final int SCREENLAYOUT_ROUND_UNDEFINED = 0x00;
    248     /**
    249      * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating
    250      * that the screen does not have a rounded shape.
    251      */
    252     public static final int SCREENLAYOUT_ROUND_NO = 0x1 << SCREENLAYOUT_ROUND_SHIFT;
    253     /**
    254      * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating
    255      * that the screen has a rounded shape. Corners may not be visible to the user;
    256      * developers should pay special attention to the {@link android.view.WindowInsets} delivered
    257      * to views for more information about ensuring content is not obscured.
    258      *
    259      * <p>Corresponds to the <code>-round</code> resource qualifier.</p>
    260      */
    261     public static final int SCREENLAYOUT_ROUND_YES = 0x2 << SCREENLAYOUT_ROUND_SHIFT;
    262 
    263     /** Constant for {@link #screenLayout}: a value indicating that screenLayout is undefined */
    264     public static final int SCREENLAYOUT_UNDEFINED = SCREENLAYOUT_SIZE_UNDEFINED |
    265             SCREENLAYOUT_LONG_UNDEFINED | SCREENLAYOUT_LAYOUTDIR_UNDEFINED |
    266             SCREENLAYOUT_ROUND_UNDEFINED;
    267 
    268     /**
    269      * Special flag we generate to indicate that the screen layout requires
    270      * us to use a compatibility mode for apps that are not modern layout
    271      * aware.
    272      * @hide
    273      */
    274     public static final int SCREENLAYOUT_COMPAT_NEEDED = 0x10000000;
    275 
    276     /**
    277      * Bit mask of overall layout of the screen.  Currently there are four
    278      * fields:
    279      * <p>The {@link #SCREENLAYOUT_SIZE_MASK} bits define the overall size
    280      * of the screen.  They may be one of
    281      * {@link #SCREENLAYOUT_SIZE_SMALL}, {@link #SCREENLAYOUT_SIZE_NORMAL},
    282      * {@link #SCREENLAYOUT_SIZE_LARGE}, or {@link #SCREENLAYOUT_SIZE_XLARGE}.</p>
    283      *
    284      * <p>The {@link #SCREENLAYOUT_LONG_MASK} defines whether the screen
    285      * is wider/taller than normal.  They may be one of
    286      * {@link #SCREENLAYOUT_LONG_NO} or {@link #SCREENLAYOUT_LONG_YES}.</p>
    287      *
    288      * <p>The {@link #SCREENLAYOUT_LAYOUTDIR_MASK} defines whether the screen layout
    289      * is either LTR or RTL.  They may be one of
    290      * {@link #SCREENLAYOUT_LAYOUTDIR_LTR} or {@link #SCREENLAYOUT_LAYOUTDIR_RTL}.</p>
    291      *
    292      * <p>The {@link #SCREENLAYOUT_ROUND_MASK} defines whether the screen has a rounded
    293      * shape. They may be one of {@link #SCREENLAYOUT_ROUND_NO} or {@link #SCREENLAYOUT_ROUND_YES}.
    294      * </p>
    295      *
    296      * <p>See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
    297      * Multiple Screens</a> for more information.</p>
    298      */
    299     public int screenLayout;
    300 
    301     /**
    302      * @hide
    303      * {@link android.graphics.Rect} defining app bounds. The dimensions override usages of
    304      * {@link DisplayInfo#appHeight} and {@link DisplayInfo#appWidth} and mirrors these values at
    305      * the display level. Lower levels can override these values to provide custom bounds to enforce
    306      * features such as a max aspect ratio.
    307      * TODO(b/36812336): Move appBounds out of {@link Configuration}.
    308      */
    309     public Rect appBounds;
    310 
    311     /** @hide */
    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