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