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