1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.content.res;
18
19import android.content.pm.ActivityInfo;
20import android.os.Parcel;
21import android.os.Parcelable;
22import android.text.TextUtils;
23import android.view.View;
24
25import java.util.Locale;
26
27/**
28 * This class describes all device configuration information that can
29 * impact the resources the application retrieves.  This includes both
30 * user-specified configuration options (locale and scaling) as well
31 * as device configurations (such as input modes, screen size and screen orientation).
32 * <p>You can acquire this object from {@link Resources}, using {@link
33 * Resources#getConfiguration}. Thus, from an activity, you can get it by chaining the request
34 * with {@link android.app.Activity#getResources}:</p>
35 * <pre>Configuration config = getResources().getConfiguration();</pre>
36 */
37public final class Configuration implements Parcelable, Comparable<Configuration> {
38    /** @hide */
39    public static final Configuration EMPTY = new Configuration();
40
41    /**
42     * Current user preference for the scaling factor for fonts, relative
43     * to the base density scaling.
44     */
45    public float fontScale;
46
47    /**
48     * IMSI MCC (Mobile Country Code), corresponding to
49     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mcc</a>
50     * resource qualifier.  0 if undefined.
51     */
52    public int mcc;
53
54    /**
55     * IMSI MNC (Mobile Network Code), corresponding to
56     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mnc</a>
57     * resource qualifier.  0 if undefined.
58     */
59    public int mnc;
60
61    /**
62     * Current user preference for the locale, corresponding to
63     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a>
64     * resource qualifier.
65     */
66    public Locale locale;
67
68    /**
69     * Locale should persist on setting.  This is hidden because it is really
70     * questionable whether this is the right way to expose the functionality.
71     * @hide
72     */
73    public boolean userSetLocale;
74
75    /** Constant for {@link #screenLayout}: bits that encode the size. */
76    public static final int SCREENLAYOUT_SIZE_MASK = 0x0f;
77    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
78     * value indicating that no size has been set. */
79    public static final int SCREENLAYOUT_SIZE_UNDEFINED = 0x00;
80    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
81     * value indicating the screen is at least approximately 320x426 dp units,
82     * corresponds to the
83     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">small</a>
84     * resource qualifier.
85     * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
86     * Multiple Screens</a> for more information. */
87    public static final int SCREENLAYOUT_SIZE_SMALL = 0x01;
88    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
89     * value indicating the screen is at least approximately 320x470 dp units,
90     * corresponds to the
91     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">normal</a>
92     * resource qualifier.
93     * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
94     * Multiple Screens</a> for more information. */
95    public static final int SCREENLAYOUT_SIZE_NORMAL = 0x02;
96    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
97     * value indicating the screen is at least approximately 480x640 dp units,
98     * corresponds to the
99     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">large</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_LARGE = 0x03;
104    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
105     * value indicating the screen is at least approximately 720x960 dp units,
106     * corresponds to the
107     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">xlarge</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_XLARGE = 0x04;
112
113    /** Constant for {@link #screenLayout}: bits that encode the aspect ratio. */
114    public static final int SCREENLAYOUT_LONG_MASK = 0x30;
115    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK}
116     * value indicating that no size has been set. */
117    public static final int SCREENLAYOUT_LONG_UNDEFINED = 0x00;
118    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK}
119     * value that corresponds to the
120     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenAspectQualifier">notlong</a>
121     * resource qualifier. */
122    public static final int SCREENLAYOUT_LONG_NO = 0x10;
123    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK}
124     * value that corresponds to the
125     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenAspectQualifier">long</a>
126     * resource qualifier. */
127    public static final int SCREENLAYOUT_LONG_YES = 0x20;
128
129    /** Constant for {@link #screenLayout}: bits that encode the layout direction. */
130    public static final int SCREENLAYOUT_LAYOUTDIR_MASK = 0xC0;
131    /** Constant for {@link #screenLayout}: bits shift to get the layout direction. */
132    public static final int SCREENLAYOUT_LAYOUTDIR_SHIFT = 6;
133    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK}
134     * value indicating that no layout dir has been set. */
135    public static final int SCREENLAYOUT_LAYOUTDIR_UNDEFINED = 0x00;
136    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK}
137     * value indicating that a layout dir has been set to LTR. */
138    public static final int SCREENLAYOUT_LAYOUTDIR_LTR = 0x01 << SCREENLAYOUT_LAYOUTDIR_SHIFT;
139    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK}
140     * value indicating that a layout dir has been set to RTL. */
141    public static final int SCREENLAYOUT_LAYOUTDIR_RTL = 0x02 << SCREENLAYOUT_LAYOUTDIR_SHIFT;
142
143    /** Constant for {@link #screenLayout}: a value indicating that screenLayout is undefined */
144    public static final int SCREENLAYOUT_UNDEFINED = SCREENLAYOUT_SIZE_UNDEFINED |
145            SCREENLAYOUT_LONG_UNDEFINED | SCREENLAYOUT_LAYOUTDIR_UNDEFINED;
146
147    /**
148     * Special flag we generate to indicate that the screen layout requires
149     * us to use a compatibility mode for apps that are not modern layout
150     * aware.
151     * @hide
152     */
153    public static final int SCREENLAYOUT_COMPAT_NEEDED = 0x10000000;
154
155    /**
156     * Bit mask of overall layout of the screen.  Currently there are two
157     * fields:
158     * <p>The {@link #SCREENLAYOUT_SIZE_MASK} bits define the overall size
159     * of the screen.  They may be one of
160     * {@link #SCREENLAYOUT_SIZE_SMALL}, {@link #SCREENLAYOUT_SIZE_NORMAL},
161     * {@link #SCREENLAYOUT_SIZE_LARGE}, or {@link #SCREENLAYOUT_SIZE_XLARGE}.
162     *
163     * <p>The {@link #SCREENLAYOUT_LONG_MASK} defines whether the screen
164     * is wider/taller than normal.  They may be one of
165     * {@link #SCREENLAYOUT_LONG_NO} or {@link #SCREENLAYOUT_LONG_YES}.
166     *
167     * <p>The {@link #SCREENLAYOUT_LAYOUTDIR_MASK} defines whether the screen layout
168     * is either LTR or RTL.  They may be one of
169     * {@link #SCREENLAYOUT_LAYOUTDIR_LTR} or {@link #SCREENLAYOUT_LAYOUTDIR_RTL}.
170     *
171     * <p>See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
172     * Multiple Screens</a> for more information.
173     */
174    public int screenLayout;
175
176    /** @hide */
177    static public int resetScreenLayout(int curLayout) {
178        return (curLayout&~(SCREENLAYOUT_LONG_MASK | SCREENLAYOUT_SIZE_MASK
179                        | SCREENLAYOUT_COMPAT_NEEDED))
180                | (SCREENLAYOUT_LONG_YES | SCREENLAYOUT_SIZE_XLARGE);
181    }
182
183    /** @hide */
184    static public int reduceScreenLayout(int curLayout, int longSizeDp, int shortSizeDp) {
185        int screenLayoutSize;
186        boolean screenLayoutLong;
187        boolean screenLayoutCompatNeeded;
188
189        // These semi-magic numbers define our compatibility modes for
190        // applications with different screens.  These are guarantees to
191        // app developers about the space they can expect for a particular
192        // configuration.  DO NOT CHANGE!
193        if (longSizeDp < 470) {
194            // This is shorter than an HVGA normal density screen (which
195            // is 480 pixels on its long side).
196            screenLayoutSize = SCREENLAYOUT_SIZE_SMALL;
197            screenLayoutLong = false;
198            screenLayoutCompatNeeded = false;
199        } else {
200            // What size is this screen screen?
201            if (longSizeDp >= 960 && shortSizeDp >= 720) {
202                // 1.5xVGA or larger screens at medium density are the point
203                // at which we consider it to be an extra large screen.
204                screenLayoutSize = SCREENLAYOUT_SIZE_XLARGE;
205            } else if (longSizeDp >= 640 && shortSizeDp >= 480) {
206                // VGA or larger screens at medium density are the point
207                // at which we consider it to be a large screen.
208                screenLayoutSize = SCREENLAYOUT_SIZE_LARGE;
209            } else {
210                screenLayoutSize = SCREENLAYOUT_SIZE_NORMAL;
211            }
212
213            // If this screen is wider than normal HVGA, or taller
214            // than FWVGA, then for old apps we want to run in size
215            // compatibility mode.
216            if (shortSizeDp > 321 || longSizeDp > 570) {
217                screenLayoutCompatNeeded = true;
218            } else {
219                screenLayoutCompatNeeded = false;
220            }
221
222            // Is this a long screen?
223            if (((longSizeDp*3)/5) >= (shortSizeDp-1)) {
224                // Anything wider than WVGA (5:3) is considering to be long.
225                screenLayoutLong = true;
226            } else {
227                screenLayoutLong = false;
228            }
229        }
230
231        // Now reduce the last screenLayout to not be better than what we
232        // have found.
233        if (!screenLayoutLong) {
234            curLayout = (curLayout&~SCREENLAYOUT_LONG_MASK) | SCREENLAYOUT_LONG_NO;
235        }
236        if (screenLayoutCompatNeeded) {
237            curLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
238        }
239        int curSize = curLayout&SCREENLAYOUT_SIZE_MASK;
240        if (screenLayoutSize < curSize) {
241            curLayout = (curLayout&~SCREENLAYOUT_SIZE_MASK) | screenLayoutSize;
242        }
243        return curLayout;
244    }
245
246    /**
247     * Check if the Configuration's current {@link #screenLayout} is at
248     * least the given size.
249     *
250     * @param size The desired size, either {@link #SCREENLAYOUT_SIZE_SMALL},
251     * {@link #SCREENLAYOUT_SIZE_NORMAL}, {@link #SCREENLAYOUT_SIZE_LARGE}, or
252     * {@link #SCREENLAYOUT_SIZE_XLARGE}.
253     * @return Returns true if the current screen layout size is at least
254     * the given size.
255     */
256    public boolean isLayoutSizeAtLeast(int size) {
257        int cur = screenLayout&SCREENLAYOUT_SIZE_MASK;
258        if (cur == SCREENLAYOUT_SIZE_UNDEFINED) return false;
259        return cur >= size;
260    }
261
262    /** Constant for {@link #touchscreen}: a value indicating that no value has been set. */
263    public static final int TOUCHSCREEN_UNDEFINED = 0;
264    /** Constant for {@link #touchscreen}, value corresponding to the
265     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#TouchscreenQualifier">notouch</a>
266     * resource qualifier. */
267    public static final int TOUCHSCREEN_NOTOUCH = 1;
268    /** @deprecated Not currently supported or used. */
269    @Deprecated public static final int TOUCHSCREEN_STYLUS = 2;
270    /** Constant for {@link #touchscreen}, value corresponding to the
271     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#TouchscreenQualifier">finger</a>
272     * resource qualifier. */
273    public static final int TOUCHSCREEN_FINGER = 3;
274
275    /**
276     * The kind of touch screen attached to the device.
277     * One of: {@link #TOUCHSCREEN_NOTOUCH}, {@link #TOUCHSCREEN_FINGER}.
278     */
279    public int touchscreen;
280
281    /** Constant for {@link #keyboard}: a value indicating that no value has been set. */
282    public static final int KEYBOARD_UNDEFINED = 0;
283    /** Constant for {@link #keyboard}, value corresponding to the
284     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">nokeys</a>
285     * resource qualifier. */
286    public static final int KEYBOARD_NOKEYS = 1;
287    /** Constant for {@link #keyboard}, value corresponding to the
288     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">qwerty</a>
289     * resource qualifier. */
290    public static final int KEYBOARD_QWERTY = 2;
291    /** Constant for {@link #keyboard}, value corresponding to the
292     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">12key</a>
293     * resource qualifier. */
294    public static final int KEYBOARD_12KEY = 3;
295
296    /**
297     * The kind of keyboard attached to the device.
298     * One of: {@link #KEYBOARD_NOKEYS}, {@link #KEYBOARD_QWERTY},
299     * {@link #KEYBOARD_12KEY}.
300     */
301    public int keyboard;
302
303    /** Constant for {@link #keyboardHidden}: a value indicating that no value has been set. */
304    public static final int KEYBOARDHIDDEN_UNDEFINED = 0;
305    /** Constant for {@link #keyboardHidden}, value corresponding to the
306     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keysexposed</a>
307     * resource qualifier. */
308    public static final int KEYBOARDHIDDEN_NO = 1;
309    /** Constant for {@link #keyboardHidden}, value corresponding to the
310     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keyshidden</a>
311     * resource qualifier. */
312    public static final int KEYBOARDHIDDEN_YES = 2;
313    /** Constant matching actual resource implementation. {@hide} */
314    public static final int KEYBOARDHIDDEN_SOFT = 3;
315
316    /**
317     * A flag indicating whether any keyboard is available.  Unlike
318     * {@link #hardKeyboardHidden}, this also takes into account a soft
319     * keyboard, so if the hard keyboard is hidden but there is soft
320     * keyboard available, it will be set to NO.  Value is one of:
321     * {@link #KEYBOARDHIDDEN_NO}, {@link #KEYBOARDHIDDEN_YES}.
322     */
323    public int keyboardHidden;
324
325    /** Constant for {@link #hardKeyboardHidden}: a value indicating that no value has been set. */
326    public static final int HARDKEYBOARDHIDDEN_UNDEFINED = 0;
327    /** Constant for {@link #hardKeyboardHidden}, value corresponding to the
328     * physical keyboard being exposed. */
329    public static final int HARDKEYBOARDHIDDEN_NO = 1;
330    /** Constant for {@link #hardKeyboardHidden}, value corresponding to the
331     * physical keyboard being hidden. */
332    public static final int HARDKEYBOARDHIDDEN_YES = 2;
333
334    /**
335     * A flag indicating whether the hard keyboard has been hidden.  This will
336     * be set on a device with a mechanism to hide the keyboard from the
337     * user, when that mechanism is closed.  One of:
338     * {@link #HARDKEYBOARDHIDDEN_NO}, {@link #HARDKEYBOARDHIDDEN_YES}.
339     */
340    public int hardKeyboardHidden;
341
342    /** Constant for {@link #navigation}: a value indicating that no value has been set. */
343    public static final int NAVIGATION_UNDEFINED = 0;
344    /** Constant for {@link #navigation}, value corresponding to the
345     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">nonav</a>
346     * resource qualifier. */
347    public static final int NAVIGATION_NONAV = 1;
348    /** Constant for {@link #navigation}, value corresponding to the
349     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">dpad</a>
350     * resource qualifier. */
351    public static final int NAVIGATION_DPAD = 2;
352    /** Constant for {@link #navigation}, value corresponding to the
353     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">trackball</a>
354     * resource qualifier. */
355    public static final int NAVIGATION_TRACKBALL = 3;
356    /** Constant for {@link #navigation}, value corresponding to the
357     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">wheel</a>
358     * resource qualifier. */
359    public static final int NAVIGATION_WHEEL = 4;
360
361    /**
362     * The kind of navigation method available on the device.
363     * One of: {@link #NAVIGATION_NONAV}, {@link #NAVIGATION_DPAD},
364     * {@link #NAVIGATION_TRACKBALL}, {@link #NAVIGATION_WHEEL}.
365     */
366    public int navigation;
367
368    /** Constant for {@link #navigationHidden}: a value indicating that no value has been set. */
369    public static final int NAVIGATIONHIDDEN_UNDEFINED = 0;
370    /** Constant for {@link #navigationHidden}, value corresponding to the
371     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavAvailQualifier">navexposed</a>
372     * resource qualifier. */
373    public static final int NAVIGATIONHIDDEN_NO = 1;
374    /** Constant for {@link #navigationHidden}, value corresponding to the
375     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavAvailQualifier">navhidden</a>
376     * resource qualifier. */
377    public static final int NAVIGATIONHIDDEN_YES = 2;
378
379    /**
380     * A flag indicating whether any 5-way or DPAD navigation available.
381     * This will be set on a device with a mechanism to hide the navigation
382     * controls from the user, when that mechanism is closed.  One of:
383     * {@link #NAVIGATIONHIDDEN_NO}, {@link #NAVIGATIONHIDDEN_YES}.
384     */
385    public int navigationHidden;
386
387    /** Constant for {@link #orientation}: a value indicating that no value has been set. */
388    public static final int ORIENTATION_UNDEFINED = 0;
389    /** Constant for {@link #orientation}, value corresponding to the
390     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#OrientationQualifier">port</a>
391     * resource qualifier. */
392    public static final int ORIENTATION_PORTRAIT = 1;
393    /** Constant for {@link #orientation}, value corresponding to the
394     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#OrientationQualifier">land</a>
395     * resource qualifier. */
396    public static final int ORIENTATION_LANDSCAPE = 2;
397    /** @deprecated Not currently supported or used. */
398    @Deprecated public static final int ORIENTATION_SQUARE = 3;
399
400    /**
401     * Overall orientation of the screen.  May be one of
402     * {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}.
403     */
404    public int orientation;
405
406    /** Constant for {@link #uiMode}: bits that encode the mode type. */
407    public static final int UI_MODE_TYPE_MASK = 0x0f;
408    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
409     * value indicating that no mode type has been set. */
410    public static final int UI_MODE_TYPE_UNDEFINED = 0x00;
411    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
412     * value that corresponds to
413     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">no
414     * UI mode</a> resource qualifier specified. */
415    public static final int UI_MODE_TYPE_NORMAL = 0x01;
416    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
417     * value that corresponds to the
418     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">desk</a>
419     * resource qualifier. */
420    public static final int UI_MODE_TYPE_DESK = 0x02;
421    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
422     * value that corresponds to the
423     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">car</a>
424     * resource qualifier. */
425    public static final int UI_MODE_TYPE_CAR = 0x03;
426    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
427     * value that corresponds to the
428     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">television</a>
429     * resource qualifier. */
430    public static final int UI_MODE_TYPE_TELEVISION = 0x04;
431    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
432     * value that corresponds to the
433     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">appliance</a>
434     * resource qualifier. */
435    public static final int UI_MODE_TYPE_APPLIANCE = 0x05;
436
437    /** Constant for {@link #uiMode}: bits that encode the night mode. */
438    public static final int UI_MODE_NIGHT_MASK = 0x30;
439    /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK}
440     * value indicating that no mode type has been set. */
441    public static final int UI_MODE_NIGHT_UNDEFINED = 0x00;
442    /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK}
443     * value that corresponds to the
444     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NightQualifier">notnight</a>
445     * resource qualifier. */
446    public static final int UI_MODE_NIGHT_NO = 0x10;
447    /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK}
448     * value that corresponds to the
449     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NightQualifier">night</a>
450     * resource qualifier. */
451    public static final int UI_MODE_NIGHT_YES = 0x20;
452
453    /**
454     * Bit mask of the ui mode.  Currently there are two fields:
455     * <p>The {@link #UI_MODE_TYPE_MASK} bits define the overall ui mode of the
456     * device. They may be one of {@link #UI_MODE_TYPE_UNDEFINED},
457     * {@link #UI_MODE_TYPE_NORMAL}, {@link #UI_MODE_TYPE_DESK},
458     * {@link #UI_MODE_TYPE_CAR}, {@link #UI_MODE_TYPE_TELEVISION}, or
459     * {@link #UI_MODE_TYPE_APPLIANCE}.
460     *
461     * <p>The {@link #UI_MODE_NIGHT_MASK} defines whether the screen
462     * is in a special mode. They may be one of {@link #UI_MODE_NIGHT_UNDEFINED},
463     * {@link #UI_MODE_NIGHT_NO} or {@link #UI_MODE_NIGHT_YES}.
464     */
465    public int uiMode;
466
467    /**
468     * Default value for {@link #screenWidthDp} indicating that no width
469     * has been specified.
470     */
471    public static final int SCREEN_WIDTH_DP_UNDEFINED = 0;
472
473    /**
474     * The current width of the available screen space, in dp units,
475     * corresponding to
476     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenWidthQualifier">screen
477     * width</a> resource qualifier.  Set to
478     * {@link #SCREEN_WIDTH_DP_UNDEFINED} if no width is specified.
479     */
480    public int screenWidthDp;
481
482    /**
483     * Default value for {@link #screenHeightDp} indicating that no width
484     * has been specified.
485     */
486    public static final int SCREEN_HEIGHT_DP_UNDEFINED = 0;
487
488    /**
489     * The current height of the available screen space, in dp units,
490     * corresponding to
491     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenHeightQualifier">screen
492     * height</a> resource qualifier.  Set to
493     * {@link #SCREEN_HEIGHT_DP_UNDEFINED} if no height is specified.
494     */
495    public int screenHeightDp;
496
497    /**
498     * Default value for {@link #smallestScreenWidthDp} indicating that no width
499     * has been specified.
500     */
501    public static final int SMALLEST_SCREEN_WIDTH_DP_UNDEFINED = 0;
502
503    /**
504     * The smallest screen size an application will see in normal operation,
505     * corresponding to
506     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#SmallestScreenWidthQualifier">smallest
507     * screen width</a> resource qualifier.
508     * This is the smallest value of both screenWidthDp and screenHeightDp
509     * in both portrait and landscape.  Set to
510     * {@link #SMALLEST_SCREEN_WIDTH_DP_UNDEFINED} if no width is specified.
511     */
512    public int smallestScreenWidthDp;
513
514    /**
515     * Default value for {@link #densityDpi} indicating that no width
516     * has been specified.
517     */
518    public static final int DENSITY_DPI_UNDEFINED = 0;
519
520    /**
521     * The target screen density being rendered to,
522     * corresponding to
523     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#DensityQualifier">density</a>
524     * resource qualifier.  Set to
525     * {@link #DENSITY_DPI_UNDEFINED} if no density is specified.
526     */
527    public int densityDpi;
528
529    /** @hide Hack to get this information from WM to app running in compat mode. */
530    public int compatScreenWidthDp;
531    /** @hide Hack to get this information from WM to app running in compat mode. */
532    public int compatScreenHeightDp;
533    /** @hide Hack to get this information from WM to app running in compat mode. */
534    public int compatSmallestScreenWidthDp;
535
536    /**
537     * @hide Internal book-keeping.
538     */
539    public int seq;
540
541    /**
542     * Construct an invalid Configuration.  You must call {@link #setToDefaults}
543     * for this object to be valid.  {@more}
544     */
545    public Configuration() {
546        setToDefaults();
547    }
548
549    /**
550     * Makes a deep copy suitable for modification.
551     */
552    public Configuration(Configuration o) {
553        setTo(o);
554    }
555
556    public void setTo(Configuration o) {
557        fontScale = o.fontScale;
558        mcc = o.mcc;
559        mnc = o.mnc;
560        if (o.locale != null) {
561            locale = (Locale) o.locale.clone();
562        }
563        userSetLocale = o.userSetLocale;
564        touchscreen = o.touchscreen;
565        keyboard = o.keyboard;
566        keyboardHidden = o.keyboardHidden;
567        hardKeyboardHidden = o.hardKeyboardHidden;
568        navigation = o.navigation;
569        navigationHidden = o.navigationHidden;
570        orientation = o.orientation;
571        screenLayout = o.screenLayout;
572        uiMode = o.uiMode;
573        screenWidthDp = o.screenWidthDp;
574        screenHeightDp = o.screenHeightDp;
575        smallestScreenWidthDp = o.smallestScreenWidthDp;
576        densityDpi = o.densityDpi;
577        compatScreenWidthDp = o.compatScreenWidthDp;
578        compatScreenHeightDp = o.compatScreenHeightDp;
579        compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp;
580        seq = o.seq;
581    }
582
583    public String toString() {
584        StringBuilder sb = new StringBuilder(128);
585        sb.append("{");
586        sb.append(fontScale);
587        sb.append(" ");
588        if (mcc != 0) {
589            sb.append(mcc);
590            sb.append("mcc");
591        } else {
592            sb.append("?mcc");
593        }
594        if (mnc != 0) {
595            sb.append(mnc);
596            sb.append("mnc");
597        } else {
598            sb.append("?mnc");
599        }
600        if (locale != null) {
601            sb.append(" ");
602            sb.append(locale);
603        } else {
604            sb.append(" ?locale");
605        }
606        int layoutDir = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK);
607        switch (layoutDir) {
608            case SCREENLAYOUT_LAYOUTDIR_UNDEFINED: sb.append(" ?layoutDir"); break;
609            case SCREENLAYOUT_LAYOUTDIR_LTR: sb.append(" ldltr"); break;
610            case SCREENLAYOUT_LAYOUTDIR_RTL: sb.append(" ldrtl"); break;
611            default: sb.append(" layoutDir=");
612                sb.append(layoutDir >> SCREENLAYOUT_LAYOUTDIR_SHIFT); break;
613        }
614        if (smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
615            sb.append(" sw"); sb.append(smallestScreenWidthDp); sb.append("dp");
616        } else {
617            sb.append(" ?swdp");
618        }
619        if (screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) {
620            sb.append(" w"); sb.append(screenWidthDp); sb.append("dp");
621        } else {
622            sb.append(" ?wdp");
623        }
624        if (screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) {
625            sb.append(" h"); sb.append(screenHeightDp); sb.append("dp");
626        } else {
627            sb.append(" ?hdp");
628        }
629        if (densityDpi != DENSITY_DPI_UNDEFINED) {
630            sb.append(" "); sb.append(densityDpi); sb.append("dpi");
631        } else {
632            sb.append(" ?density");
633        }
634        switch ((screenLayout&SCREENLAYOUT_SIZE_MASK)) {
635            case SCREENLAYOUT_SIZE_UNDEFINED: sb.append(" ?lsize"); break;
636            case SCREENLAYOUT_SIZE_SMALL: sb.append(" smll"); break;
637            case SCREENLAYOUT_SIZE_NORMAL: sb.append(" nrml"); break;
638            case SCREENLAYOUT_SIZE_LARGE: sb.append(" lrg"); break;
639            case SCREENLAYOUT_SIZE_XLARGE: sb.append(" xlrg"); break;
640            default: sb.append(" layoutSize=");
641                    sb.append(screenLayout&SCREENLAYOUT_SIZE_MASK); break;
642        }
643        switch ((screenLayout&SCREENLAYOUT_LONG_MASK)) {
644            case SCREENLAYOUT_LONG_UNDEFINED: sb.append(" ?long"); break;
645            case SCREENLAYOUT_LONG_NO: /* not-long is not interesting to print */ break;
646            case SCREENLAYOUT_LONG_YES: sb.append(" long"); break;
647            default: sb.append(" layoutLong=");
648                    sb.append(screenLayout&SCREENLAYOUT_LONG_MASK); break;
649        }
650        switch (orientation) {
651            case ORIENTATION_UNDEFINED: sb.append(" ?orien"); break;
652            case ORIENTATION_LANDSCAPE: sb.append(" land"); break;
653            case ORIENTATION_PORTRAIT: sb.append(" port"); break;
654            default: sb.append(" orien="); sb.append(orientation); break;
655        }
656        switch ((uiMode&UI_MODE_TYPE_MASK)) {
657            case UI_MODE_TYPE_UNDEFINED: sb.append(" ?uimode"); break;
658            case UI_MODE_TYPE_NORMAL: /* normal is not interesting to print */ break;
659            case UI_MODE_TYPE_DESK: sb.append(" desk"); break;
660            case UI_MODE_TYPE_CAR: sb.append(" car"); break;
661            case UI_MODE_TYPE_TELEVISION: sb.append(" television"); break;
662            case UI_MODE_TYPE_APPLIANCE: sb.append(" appliance"); break;
663            default: sb.append(" uimode="); sb.append(uiMode&UI_MODE_TYPE_MASK); break;
664        }
665        switch ((uiMode&UI_MODE_NIGHT_MASK)) {
666            case UI_MODE_NIGHT_UNDEFINED: sb.append(" ?night"); break;
667            case UI_MODE_NIGHT_NO: /* not-night is not interesting to print */ break;
668            case UI_MODE_NIGHT_YES: sb.append(" night"); break;
669            default: sb.append(" night="); sb.append(uiMode&UI_MODE_NIGHT_MASK); break;
670        }
671        switch (touchscreen) {
672            case TOUCHSCREEN_UNDEFINED: sb.append(" ?touch"); break;
673            case TOUCHSCREEN_NOTOUCH: sb.append(" -touch"); break;
674            case TOUCHSCREEN_STYLUS: sb.append(" stylus"); break;
675            case TOUCHSCREEN_FINGER: sb.append(" finger"); break;
676            default: sb.append(" touch="); sb.append(touchscreen); break;
677        }
678        switch (keyboard) {
679            case KEYBOARD_UNDEFINED: sb.append(" ?keyb"); break;
680            case KEYBOARD_NOKEYS: sb.append(" -keyb"); break;
681            case KEYBOARD_QWERTY: sb.append(" qwerty"); break;
682            case KEYBOARD_12KEY: sb.append(" 12key"); break;
683            default: sb.append(" keys="); sb.append(keyboard); break;
684        }
685        switch (keyboardHidden) {
686            case KEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break;
687            case KEYBOARDHIDDEN_NO: sb.append("/v"); break;
688            case KEYBOARDHIDDEN_YES: sb.append("/h"); break;
689            case KEYBOARDHIDDEN_SOFT: sb.append("/s"); break;
690            default: sb.append("/"); sb.append(keyboardHidden); break;
691        }
692        switch (hardKeyboardHidden) {
693            case HARDKEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break;
694            case HARDKEYBOARDHIDDEN_NO: sb.append("/v"); break;
695            case HARDKEYBOARDHIDDEN_YES: sb.append("/h"); break;
696            default: sb.append("/"); sb.append(hardKeyboardHidden); break;
697        }
698        switch (navigation) {
699            case NAVIGATION_UNDEFINED: sb.append(" ?nav"); break;
700            case NAVIGATION_NONAV: sb.append(" -nav"); break;
701            case NAVIGATION_DPAD: sb.append(" dpad"); break;
702            case NAVIGATION_TRACKBALL: sb.append(" tball"); break;
703            case NAVIGATION_WHEEL: sb.append(" wheel"); break;
704            default: sb.append(" nav="); sb.append(navigation); break;
705        }
706        switch (navigationHidden) {
707            case NAVIGATIONHIDDEN_UNDEFINED: sb.append("/?"); break;
708            case NAVIGATIONHIDDEN_NO: sb.append("/v"); break;
709            case NAVIGATIONHIDDEN_YES: sb.append("/h"); break;
710            default: sb.append("/"); sb.append(navigationHidden); break;
711        }
712        if (seq != 0) {
713            sb.append(" s.");
714            sb.append(seq);
715        }
716        sb.append('}');
717        return sb.toString();
718    }
719
720    /**
721     * Set this object to the system defaults.
722     */
723    public void setToDefaults() {
724        fontScale = 1;
725        mcc = mnc = 0;
726        locale = null;
727        userSetLocale = false;
728        touchscreen = TOUCHSCREEN_UNDEFINED;
729        keyboard = KEYBOARD_UNDEFINED;
730        keyboardHidden = KEYBOARDHIDDEN_UNDEFINED;
731        hardKeyboardHidden = HARDKEYBOARDHIDDEN_UNDEFINED;
732        navigation = NAVIGATION_UNDEFINED;
733        navigationHidden = NAVIGATIONHIDDEN_UNDEFINED;
734        orientation = ORIENTATION_UNDEFINED;
735        screenLayout = SCREENLAYOUT_UNDEFINED;
736        uiMode = UI_MODE_TYPE_UNDEFINED;
737        screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
738        screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
739        smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
740        densityDpi = DENSITY_DPI_UNDEFINED;
741        seq = 0;
742    }
743
744    /** {@hide} */
745    @Deprecated public void makeDefault() {
746        setToDefaults();
747    }
748
749    /**
750     * Copy the fields from delta into this Configuration object, keeping
751     * track of which ones have changed.  Any undefined fields in
752     * <var>delta</var> are ignored and not copied in to the current
753     * Configuration.
754     * @return Returns a bit mask of the changed fields, as per
755     * {@link #diff}.
756     */
757    public int updateFrom(Configuration delta) {
758        int changed = 0;
759        if (delta.fontScale > 0 && fontScale != delta.fontScale) {
760            changed |= ActivityInfo.CONFIG_FONT_SCALE;
761            fontScale = delta.fontScale;
762        }
763        if (delta.mcc != 0 && mcc != delta.mcc) {
764            changed |= ActivityInfo.CONFIG_MCC;
765            mcc = delta.mcc;
766        }
767        if (delta.mnc != 0 && mnc != delta.mnc) {
768            changed |= ActivityInfo.CONFIG_MNC;
769            mnc = delta.mnc;
770        }
771        if (delta.locale != null
772                && (locale == null || !locale.equals(delta.locale))) {
773            changed |= ActivityInfo.CONFIG_LOCALE;
774            locale = delta.locale != null
775                    ? (Locale) delta.locale.clone() : null;
776            // If locale has changed, then layout direction is also changed ...
777            changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
778            // ... and we need to update the layout direction (represented by the first
779            // 2 most significant bits in screenLayout).
780            setLayoutDirection(locale);
781        }
782        if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
783        {
784            userSetLocale = true;
785            changed |= ActivityInfo.CONFIG_LOCALE;
786        }
787        if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
788                && touchscreen != delta.touchscreen) {
789            changed |= ActivityInfo.CONFIG_TOUCHSCREEN;
790            touchscreen = delta.touchscreen;
791        }
792        if (delta.keyboard != KEYBOARD_UNDEFINED
793                && keyboard != delta.keyboard) {
794            changed |= ActivityInfo.CONFIG_KEYBOARD;
795            keyboard = delta.keyboard;
796        }
797        if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED
798                && keyboardHidden != delta.keyboardHidden) {
799            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
800            keyboardHidden = delta.keyboardHidden;
801        }
802        if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED
803                && hardKeyboardHidden != delta.hardKeyboardHidden) {
804            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
805            hardKeyboardHidden = delta.hardKeyboardHidden;
806        }
807        if (delta.navigation != NAVIGATION_UNDEFINED
808                && navigation != delta.navigation) {
809            changed |= ActivityInfo.CONFIG_NAVIGATION;
810            navigation = delta.navigation;
811        }
812        if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED
813                && navigationHidden != delta.navigationHidden) {
814            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
815            navigationHidden = delta.navigationHidden;
816        }
817        if (delta.orientation != ORIENTATION_UNDEFINED
818                && orientation != delta.orientation) {
819            changed |= ActivityInfo.CONFIG_ORIENTATION;
820            orientation = delta.orientation;
821        }
822        if (getScreenLayoutNoDirection(delta.screenLayout) !=
823                    (SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED)
824                && (getScreenLayoutNoDirection(screenLayout) !=
825                    getScreenLayoutNoDirection(delta.screenLayout))) {
826            changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
827            // We need to preserve the previous layout dir bits if they were defined
828            if ((delta.screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK) == 0) {
829                screenLayout = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK)|delta.screenLayout;
830            } else {
831                screenLayout = delta.screenLayout;
832            }
833        }
834        if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED)
835                && uiMode != delta.uiMode) {
836            changed |= ActivityInfo.CONFIG_UI_MODE;
837            if ((delta.uiMode&UI_MODE_TYPE_MASK) != UI_MODE_TYPE_UNDEFINED) {
838                uiMode = (uiMode&~UI_MODE_TYPE_MASK)
839                        | (delta.uiMode&UI_MODE_TYPE_MASK);
840            }
841            if ((delta.uiMode&UI_MODE_NIGHT_MASK) != UI_MODE_NIGHT_UNDEFINED) {
842                uiMode = (uiMode&~UI_MODE_NIGHT_MASK)
843                        | (delta.uiMode&UI_MODE_NIGHT_MASK);
844            }
845        }
846        if (delta.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED
847                && screenWidthDp != delta.screenWidthDp) {
848            changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
849            screenWidthDp = delta.screenWidthDp;
850        }
851        if (delta.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED
852                && screenHeightDp != delta.screenHeightDp) {
853            changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
854            screenHeightDp = delta.screenHeightDp;
855        }
856        if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
857            changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
858            smallestScreenWidthDp = delta.smallestScreenWidthDp;
859        }
860        if (delta.densityDpi != DENSITY_DPI_UNDEFINED) {
861            changed |= ActivityInfo.CONFIG_DENSITY;
862            densityDpi = delta.densityDpi;
863        }
864        if (delta.compatScreenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) {
865            compatScreenWidthDp = delta.compatScreenWidthDp;
866        }
867        if (delta.compatScreenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) {
868            compatScreenHeightDp = delta.compatScreenHeightDp;
869        }
870        if (delta.compatSmallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
871            compatSmallestScreenWidthDp = delta.compatSmallestScreenWidthDp;
872        }
873        if (delta.seq != 0) {
874            seq = delta.seq;
875        }
876
877        return changed;
878    }
879
880    /**
881     * Return a bit mask of the differences between this Configuration
882     * object and the given one.  Does not change the values of either.  Any
883     * undefined fields in <var>delta</var> are ignored.
884     * @return Returns a bit mask indicating which configuration
885     * values has changed, containing any combination of
886     * {@link android.content.pm.ActivityInfo#CONFIG_FONT_SCALE
887     * PackageManager.ActivityInfo.CONFIG_FONT_SCALE},
888     * {@link android.content.pm.ActivityInfo#CONFIG_MCC
889     * PackageManager.ActivityInfo.CONFIG_MCC},
890     * {@link android.content.pm.ActivityInfo#CONFIG_MNC
891     * PackageManager.ActivityInfo.CONFIG_MNC},
892     * {@link android.content.pm.ActivityInfo#CONFIG_LOCALE
893     * PackageManager.ActivityInfo.CONFIG_LOCALE},
894     * {@link android.content.pm.ActivityInfo#CONFIG_TOUCHSCREEN
895     * PackageManager.ActivityInfo.CONFIG_TOUCHSCREEN},
896     * {@link android.content.pm.ActivityInfo#CONFIG_KEYBOARD
897     * PackageManager.ActivityInfo.CONFIG_KEYBOARD},
898     * {@link android.content.pm.ActivityInfo#CONFIG_NAVIGATION
899     * PackageManager.ActivityInfo.CONFIG_NAVIGATION},
900     * {@link android.content.pm.ActivityInfo#CONFIG_ORIENTATION
901     * PackageManager.ActivityInfo.CONFIG_ORIENTATION},
902     * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_LAYOUT
903     * PackageManager.ActivityInfo.CONFIG_SCREEN_LAYOUT}, or
904     * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_SIZE
905     * PackageManager.ActivityInfo.CONFIG_SCREEN_SIZE}, or
906     * {@link android.content.pm.ActivityInfo#CONFIG_SMALLEST_SCREEN_SIZE
907     * PackageManager.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE}.
908     * {@link android.content.pm.ActivityInfo#CONFIG_LAYOUT_DIRECTION
909     * PackageManager.ActivityInfo.CONFIG_LAYOUT_DIRECTION}.
910     */
911    public int diff(Configuration delta) {
912        int changed = 0;
913        if (delta.fontScale > 0 && fontScale != delta.fontScale) {
914            changed |= ActivityInfo.CONFIG_FONT_SCALE;
915        }
916        if (delta.mcc != 0 && mcc != delta.mcc) {
917            changed |= ActivityInfo.CONFIG_MCC;
918        }
919        if (delta.mnc != 0 && mnc != delta.mnc) {
920            changed |= ActivityInfo.CONFIG_MNC;
921        }
922        if (delta.locale != null
923                && (locale == null || !locale.equals(delta.locale))) {
924            changed |= ActivityInfo.CONFIG_LOCALE;
925            changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
926        }
927        if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
928                && touchscreen != delta.touchscreen) {
929            changed |= ActivityInfo.CONFIG_TOUCHSCREEN;
930        }
931        if (delta.keyboard != KEYBOARD_UNDEFINED
932                && keyboard != delta.keyboard) {
933            changed |= ActivityInfo.CONFIG_KEYBOARD;
934        }
935        if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED
936                && keyboardHidden != delta.keyboardHidden) {
937            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
938        }
939        if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED
940                && hardKeyboardHidden != delta.hardKeyboardHidden) {
941            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
942        }
943        if (delta.navigation != NAVIGATION_UNDEFINED
944                && navigation != delta.navigation) {
945            changed |= ActivityInfo.CONFIG_NAVIGATION;
946        }
947        if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED
948                && navigationHidden != delta.navigationHidden) {
949            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
950        }
951        if (delta.orientation != ORIENTATION_UNDEFINED
952                && orientation != delta.orientation) {
953            changed |= ActivityInfo.CONFIG_ORIENTATION;
954        }
955        if (getScreenLayoutNoDirection(delta.screenLayout) !=
956                    (SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED)
957                && getScreenLayoutNoDirection(screenLayout) !=
958                    getScreenLayoutNoDirection(delta.screenLayout)) {
959            changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
960        }
961        if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED)
962                && uiMode != delta.uiMode) {
963            changed |= ActivityInfo.CONFIG_UI_MODE;
964        }
965        if (delta.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED
966                && screenWidthDp != delta.screenWidthDp) {
967            changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
968        }
969        if (delta.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED
970                && screenHeightDp != delta.screenHeightDp) {
971            changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
972        }
973        if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
974                && smallestScreenWidthDp != delta.smallestScreenWidthDp) {
975            changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
976        }
977        if (delta.densityDpi != DENSITY_DPI_UNDEFINED
978                && densityDpi != delta.densityDpi) {
979            changed |= ActivityInfo.CONFIG_DENSITY;
980        }
981
982        return changed;
983    }
984
985    /**
986     * Determine if a new resource needs to be loaded from the bit set of
987     * configuration changes returned by {@link #updateFrom(Configuration)}.
988     *
989     * @param configChanges The mask of changes configurations as returned by
990     * {@link #updateFrom(Configuration)}.
991     * @param interestingChanges The configuration changes that the resource
992     * can handled, as given in {@link android.util.TypedValue#changingConfigurations}.
993     *
994     * @return Return true if the resource needs to be loaded, else false.
995     */
996    public static boolean needNewResources(int configChanges, int interestingChanges) {
997        return (configChanges & (interestingChanges|ActivityInfo.CONFIG_FONT_SCALE)) != 0;
998    }
999
1000    /**
1001     * @hide Return true if the sequence of 'other' is better than this.  Assumes
1002     * that 'this' is your current sequence and 'other' is a new one you have
1003     * received some how and want to compare with what you have.
1004     */
1005    public boolean isOtherSeqNewer(Configuration other) {
1006        if (other == null) {
1007            // Sanity check.
1008            return false;
1009        }
1010        if (other.seq == 0) {
1011            // If the other sequence is not specified, then we must assume
1012            // it is newer since we don't know any better.
1013            return true;
1014        }
1015        if (seq == 0) {
1016            // If this sequence is not specified, then we also consider the
1017            // other is better.  Yes we have a preference for other.  Sue us.
1018            return true;
1019        }
1020        int diff = other.seq - seq;
1021        if (diff > 0x10000) {
1022            // If there has been a sufficiently large jump, assume the
1023            // sequence has wrapped around.
1024            return false;
1025        }
1026        return diff > 0;
1027    }
1028
1029    /**
1030     * Parcelable methods
1031     */
1032    public int describeContents() {
1033        return 0;
1034    }
1035
1036    public void writeToParcel(Parcel dest, int flags) {
1037        dest.writeFloat(fontScale);
1038        dest.writeInt(mcc);
1039        dest.writeInt(mnc);
1040        if (locale == null) {
1041            dest.writeInt(0);
1042        } else {
1043            dest.writeInt(1);
1044            dest.writeString(locale.getLanguage());
1045            dest.writeString(locale.getCountry());
1046            dest.writeString(locale.getVariant());
1047        }
1048        if(userSetLocale) {
1049            dest.writeInt(1);
1050        } else {
1051            dest.writeInt(0);
1052        }
1053        dest.writeInt(touchscreen);
1054        dest.writeInt(keyboard);
1055        dest.writeInt(keyboardHidden);
1056        dest.writeInt(hardKeyboardHidden);
1057        dest.writeInt(navigation);
1058        dest.writeInt(navigationHidden);
1059        dest.writeInt(orientation);
1060        dest.writeInt(screenLayout);
1061        dest.writeInt(uiMode);
1062        dest.writeInt(screenWidthDp);
1063        dest.writeInt(screenHeightDp);
1064        dest.writeInt(smallestScreenWidthDp);
1065        dest.writeInt(densityDpi);
1066        dest.writeInt(compatScreenWidthDp);
1067        dest.writeInt(compatScreenHeightDp);
1068        dest.writeInt(compatSmallestScreenWidthDp);
1069        dest.writeInt(seq);
1070    }
1071
1072    public void readFromParcel(Parcel source) {
1073        fontScale = source.readFloat();
1074        mcc = source.readInt();
1075        mnc = source.readInt();
1076        if (source.readInt() != 0) {
1077            locale = new Locale(source.readString(), source.readString(),
1078                    source.readString());
1079        }
1080        userSetLocale = (source.readInt()==1);
1081        touchscreen = source.readInt();
1082        keyboard = source.readInt();
1083        keyboardHidden = source.readInt();
1084        hardKeyboardHidden = source.readInt();
1085        navigation = source.readInt();
1086        navigationHidden = source.readInt();
1087        orientation = source.readInt();
1088        screenLayout = source.readInt();
1089        uiMode = source.readInt();
1090        screenWidthDp = source.readInt();
1091        screenHeightDp = source.readInt();
1092        smallestScreenWidthDp = source.readInt();
1093        densityDpi = source.readInt();
1094        compatScreenWidthDp = source.readInt();
1095        compatScreenHeightDp = source.readInt();
1096        compatSmallestScreenWidthDp = source.readInt();
1097        seq = source.readInt();
1098    }
1099
1100    public static final Parcelable.Creator<Configuration> CREATOR
1101            = new Parcelable.Creator<Configuration>() {
1102        public Configuration createFromParcel(Parcel source) {
1103            return new Configuration(source);
1104        }
1105
1106        public Configuration[] newArray(int size) {
1107            return new Configuration[size];
1108        }
1109    };
1110
1111    /**
1112     * Construct this Configuration object, reading from the Parcel.
1113     */
1114    private Configuration(Parcel source) {
1115        readFromParcel(source);
1116    }
1117
1118    public int compareTo(Configuration that) {
1119        int n;
1120        float a = this.fontScale;
1121        float b = that.fontScale;
1122        if (a < b) return -1;
1123        if (a > b) return 1;
1124        n = this.mcc - that.mcc;
1125        if (n != 0) return n;
1126        n = this.mnc - that.mnc;
1127        if (n != 0) return n;
1128        if (this.locale == null) {
1129            if (that.locale != null) return 1;
1130        } else if (that.locale == null) {
1131            return -1;
1132        } else {
1133            n = this.locale.getLanguage().compareTo(that.locale.getLanguage());
1134            if (n != 0) return n;
1135            n = this.locale.getCountry().compareTo(that.locale.getCountry());
1136            if (n != 0) return n;
1137            n = this.locale.getVariant().compareTo(that.locale.getVariant());
1138            if (n != 0) return n;
1139        }
1140        n = this.touchscreen - that.touchscreen;
1141        if (n != 0) return n;
1142        n = this.keyboard - that.keyboard;
1143        if (n != 0) return n;
1144        n = this.keyboardHidden - that.keyboardHidden;
1145        if (n != 0) return n;
1146        n = this.hardKeyboardHidden - that.hardKeyboardHidden;
1147        if (n != 0) return n;
1148        n = this.navigation - that.navigation;
1149        if (n != 0) return n;
1150        n = this.navigationHidden - that.navigationHidden;
1151        if (n != 0) return n;
1152        n = this.orientation - that.orientation;
1153        if (n != 0) return n;
1154        n = this.screenLayout - that.screenLayout;
1155        if (n != 0) return n;
1156        n = this.uiMode - that.uiMode;
1157        if (n != 0) return n;
1158        n = this.screenWidthDp - that.screenWidthDp;
1159        if (n != 0) return n;
1160        n = this.screenHeightDp - that.screenHeightDp;
1161        if (n != 0) return n;
1162        n = this.smallestScreenWidthDp - that.smallestScreenWidthDp;
1163        if (n != 0) return n;
1164        n = this.densityDpi - that.densityDpi;
1165        //if (n != 0) return n;
1166        return n;
1167    }
1168
1169    public boolean equals(Configuration that) {
1170        if (that == null) return false;
1171        if (that == this) return true;
1172        return this.compareTo(that) == 0;
1173    }
1174
1175    public boolean equals(Object that) {
1176        try {
1177            return equals((Configuration)that);
1178        } catch (ClassCastException e) {
1179        }
1180        return false;
1181    }
1182
1183    public int hashCode() {
1184        int result = 17;
1185        result = 31 * result + Float.floatToIntBits(fontScale);
1186        result = 31 * result + mcc;
1187        result = 31 * result + mnc;
1188        result = 31 * result + (locale != null ? locale.hashCode() : 0);
1189        result = 31 * result + touchscreen;
1190        result = 31 * result + keyboard;
1191        result = 31 * result + keyboardHidden;
1192        result = 31 * result + hardKeyboardHidden;
1193        result = 31 * result + navigation;
1194        result = 31 * result + navigationHidden;
1195        result = 31 * result + orientation;
1196        result = 31 * result + screenLayout;
1197        result = 31 * result + uiMode;
1198        result = 31 * result + screenWidthDp;
1199        result = 31 * result + screenHeightDp;
1200        result = 31 * result + smallestScreenWidthDp;
1201        result = 31 * result + densityDpi;
1202        return result;
1203    }
1204
1205    /**
1206     * Set the locale. This is the preferred way for setting up the locale (instead of using the
1207     * direct accessor). This will also set the userLocale and layout direction according to
1208     * the locale.
1209     *
1210     * @param loc The locale. Can be null.
1211     */
1212    public void setLocale(Locale loc) {
1213        locale = loc;
1214        userSetLocale = true;
1215        setLayoutDirection(locale);
1216    }
1217
1218    /**
1219     * Return the layout direction. Will be either {@link View#LAYOUT_DIRECTION_LTR} or
1220     * {@link View#LAYOUT_DIRECTION_RTL}.
1221     *
1222     * @return the layout direction
1223     */
1224    public int getLayoutDirection() {
1225        // We need to substract one here as the configuration values are using "0" as undefined thus
1226        // having LRT set to "1" and RTL set to "2"
1227        return ((screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK) >> SCREENLAYOUT_LAYOUTDIR_SHIFT) - 1;
1228    }
1229
1230    /**
1231     * Set the layout direction from the Locale.
1232     *
1233     * @param locale The Locale. If null will set the layout direction to
1234     * {@link View#LAYOUT_DIRECTION_LTR}. If not null will set it to the layout direction
1235     * corresponding to the Locale.
1236     *
1237     * @see {@link View#LAYOUT_DIRECTION_LTR} and {@link View#LAYOUT_DIRECTION_RTL}
1238     */
1239    public void setLayoutDirection(Locale locale) {
1240        // There is a "1" difference between the configuration values for
1241        // layout direction and View constants for layout direction, just add "1".
1242        final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(locale);
1243        screenLayout = (screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK)|
1244                (layoutDirection << SCREENLAYOUT_LAYOUTDIR_SHIFT);
1245    }
1246
1247    private static int getScreenLayoutNoDirection(int screenLayout) {
1248        return screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK;
1249    }
1250}
1251