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