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