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.util.LocaleUtil;
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    /**
39     * Current user preference for the scaling factor for fonts, relative
40     * to the base density scaling.
41     */
42    public float fontScale;
43
44    /**
45     * IMSI MCC (Mobile Country Code), corresponding to
46     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mcc</a>
47     * resource qualifier.  0 if undefined.
48     */
49    public int mcc;
50
51    /**
52     * IMSI MNC (Mobile Network Code), corresponding to
53     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mnc</a>
54     * resource qualifier.  0 if undefined.
55     */
56    public int mnc;
57
58    /**
59     * Current user preference for the locale, corresponding to
60     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a>
61     * resource qualifier.
62     */
63    public Locale locale;
64
65    /**
66     * Locale should persist on setting.  This is hidden because it is really
67     * questionable whether this is the right way to expose the functionality.
68     * @hide
69     */
70    public boolean userSetLocale;
71
72    /** Constant for {@link #screenLayout}: bits that encode the size. */
73    public static final int SCREENLAYOUT_SIZE_MASK = 0x0f;
74    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
75     * value indicating that no size has been set. */
76    public static final int SCREENLAYOUT_SIZE_UNDEFINED = 0x00;
77    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
78     * value indicating the screen is at least approximately 320x426 dp units,
79     * corresponds to the
80     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">small</a>
81     * resource qualifier.
82     * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
83     * Multiple Screens</a> for more information. */
84    public static final int SCREENLAYOUT_SIZE_SMALL = 0x01;
85    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
86     * value indicating the screen is at least approximately 320x470 dp units,
87     * corresponds to the
88     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">normal</a>
89     * resource qualifier.
90     * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
91     * Multiple Screens</a> for more information. */
92    public static final int SCREENLAYOUT_SIZE_NORMAL = 0x02;
93    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
94     * value indicating the screen is at least approximately 480x640 dp units,
95     * corresponds to the
96     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">large</a>
97     * resource qualifier.
98     * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
99     * Multiple Screens</a> for more information. */
100    public static final int SCREENLAYOUT_SIZE_LARGE = 0x03;
101    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
102     * value indicating the screen is at least approximately 720x960 dp units,
103     * corresponds to the
104     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">xlarge</a>
105     * resource qualifier.
106     * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
107     * Multiple Screens</a> for more information.*/
108    public static final int SCREENLAYOUT_SIZE_XLARGE = 0x04;
109
110    /** Constant for {@link #screenLayout}: bits that encode the aspect ratio. */
111    public static final int SCREENLAYOUT_LONG_MASK = 0x30;
112    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK}
113     * value indicating that no size has been set. */
114    public static final int SCREENLAYOUT_LONG_UNDEFINED = 0x00;
115    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK}
116     * value that corresponds to the
117     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenAspectQualifier">notlong</a>
118     * resource qualifier. */
119    public static final int SCREENLAYOUT_LONG_NO = 0x10;
120    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK}
121     * value that corresponds to the
122     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenAspectQualifier">long</a>
123     * resource qualifier. */
124    public static final int SCREENLAYOUT_LONG_YES = 0x20;
125
126    /**
127     * Special flag we generate to indicate that the screen layout requires
128     * us to use a compatibility mode for apps that are not modern layout
129     * aware.
130     * @hide
131     */
132    public static final int SCREENLAYOUT_COMPAT_NEEDED = 0x10000000;
133
134    /**
135     * Bit mask of overall layout of the screen.  Currently there are two
136     * fields:
137     * <p>The {@link #SCREENLAYOUT_SIZE_MASK} bits define the overall size
138     * of the screen.  They may be one of
139     * {@link #SCREENLAYOUT_SIZE_SMALL}, {@link #SCREENLAYOUT_SIZE_NORMAL},
140     * {@link #SCREENLAYOUT_SIZE_LARGE}, or {@link #SCREENLAYOUT_SIZE_XLARGE}.
141     *
142     * <p>The {@link #SCREENLAYOUT_LONG_MASK} defines whether the screen
143     * is wider/taller than normal.  They may be one of
144     * {@link #SCREENLAYOUT_LONG_NO} or {@link #SCREENLAYOUT_LONG_YES}.
145     *
146     * <p>See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
147     * Multiple Screens</a> for more information.
148     */
149    public int screenLayout;
150
151    /**
152     * Check if the Configuration's current {@link #screenLayout} is at
153     * least the given size.
154     *
155     * @param size The desired size, either {@link #SCREENLAYOUT_SIZE_SMALL},
156     * {@link #SCREENLAYOUT_SIZE_NORMAL}, {@link #SCREENLAYOUT_SIZE_LARGE}, or
157     * {@link #SCREENLAYOUT_SIZE_XLARGE}.
158     * @return Returns true if the current screen layout size is at least
159     * the given size.
160     */
161    public boolean isLayoutSizeAtLeast(int size) {
162        int cur = screenLayout&SCREENLAYOUT_SIZE_MASK;
163        if (cur == SCREENLAYOUT_SIZE_UNDEFINED) return false;
164        return cur >= size;
165    }
166
167    /** Constant for {@link #touchscreen}: a value indicating that no value has been set. */
168    public static final int TOUCHSCREEN_UNDEFINED = 0;
169    /** Constant for {@link #touchscreen}, value corresponding to the
170     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#TouchscreenQualifier">notouch</a>
171     * resource qualifier. */
172    public static final int TOUCHSCREEN_NOTOUCH = 1;
173    /** @deprecated Not currently supported or used. */
174    @Deprecated public static final int TOUCHSCREEN_STYLUS = 2;
175    /** Constant for {@link #touchscreen}, value corresponding to the
176     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#TouchscreenQualifier">finger</a>
177     * resource qualifier. */
178    public static final int TOUCHSCREEN_FINGER = 3;
179
180    /**
181     * The kind of touch screen attached to the device.
182     * One of: {@link #TOUCHSCREEN_NOTOUCH}, {@link #TOUCHSCREEN_FINGER}.
183     */
184    public int touchscreen;
185
186    /** Constant for {@link #keyboard}: a value indicating that no value has been set. */
187    public static final int KEYBOARD_UNDEFINED = 0;
188    /** Constant for {@link #keyboard}, value corresponding to the
189     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">nokeys</a>
190     * resource qualifier. */
191    public static final int KEYBOARD_NOKEYS = 1;
192    /** Constant for {@link #keyboard}, value corresponding to the
193     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">qwerty</a>
194     * resource qualifier. */
195    public static final int KEYBOARD_QWERTY = 2;
196    /** Constant for {@link #keyboard}, value corresponding to the
197     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">12key</a>
198     * resource qualifier. */
199    public static final int KEYBOARD_12KEY = 3;
200
201    /**
202     * The kind of keyboard attached to the device.
203     * One of: {@link #KEYBOARD_NOKEYS}, {@link #KEYBOARD_QWERTY},
204     * {@link #KEYBOARD_12KEY}.
205     */
206    public int keyboard;
207
208    /** Constant for {@link #keyboardHidden}: a value indicating that no value has been set. */
209    public static final int KEYBOARDHIDDEN_UNDEFINED = 0;
210    /** Constant for {@link #keyboardHidden}, value corresponding to the
211     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keysexposed</a>
212     * resource qualifier. */
213    public static final int KEYBOARDHIDDEN_NO = 1;
214    /** Constant for {@link #keyboardHidden}, value corresponding to the
215     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keyshidden</a>
216     * resource qualifier. */
217    public static final int KEYBOARDHIDDEN_YES = 2;
218    /** Constant matching actual resource implementation. {@hide} */
219    public static final int KEYBOARDHIDDEN_SOFT = 3;
220
221    /**
222     * A flag indicating whether any keyboard is available.  Unlike
223     * {@link #hardKeyboardHidden}, this also takes into account a soft
224     * keyboard, so if the hard keyboard is hidden but there is soft
225     * keyboard available, it will be set to NO.  Value is one of:
226     * {@link #KEYBOARDHIDDEN_NO}, {@link #KEYBOARDHIDDEN_YES}.
227     */
228    public int keyboardHidden;
229
230    /** Constant for {@link #hardKeyboardHidden}: a value indicating that no value has been set. */
231    public static final int HARDKEYBOARDHIDDEN_UNDEFINED = 0;
232    /** Constant for {@link #hardKeyboardHidden}, value corresponding to the
233     * physical keyboard being exposed. */
234    public static final int HARDKEYBOARDHIDDEN_NO = 1;
235    /** Constant for {@link #hardKeyboardHidden}, value corresponding to the
236     * physical keyboard being hidden. */
237    public static final int HARDKEYBOARDHIDDEN_YES = 2;
238
239    /**
240     * A flag indicating whether the hard keyboard has been hidden.  This will
241     * be set on a device with a mechanism to hide the keyboard from the
242     * user, when that mechanism is closed.  One of:
243     * {@link #HARDKEYBOARDHIDDEN_NO}, {@link #HARDKEYBOARDHIDDEN_YES}.
244     */
245    public int hardKeyboardHidden;
246
247    /** Constant for {@link #navigation}: a value indicating that no value has been set. */
248    public static final int NAVIGATION_UNDEFINED = 0;
249    /** Constant for {@link #navigation}, value corresponding to the
250     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">nonav</a>
251     * resource qualifier. */
252    public static final int NAVIGATION_NONAV = 1;
253    /** Constant for {@link #navigation}, value corresponding to the
254     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">dpad</a>
255     * resource qualifier. */
256    public static final int NAVIGATION_DPAD = 2;
257    /** Constant for {@link #navigation}, value corresponding to the
258     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">trackball</a>
259     * resource qualifier. */
260    public static final int NAVIGATION_TRACKBALL = 3;
261    /** Constant for {@link #navigation}, value corresponding to the
262     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">wheel</a>
263     * resource qualifier. */
264    public static final int NAVIGATION_WHEEL = 4;
265
266    /**
267     * The kind of navigation method available on the device.
268     * One of: {@link #NAVIGATION_NONAV}, {@link #NAVIGATION_DPAD},
269     * {@link #NAVIGATION_TRACKBALL}, {@link #NAVIGATION_WHEEL}.
270     */
271    public int navigation;
272
273    /** Constant for {@link #navigationHidden}: a value indicating that no value has been set. */
274    public static final int NAVIGATIONHIDDEN_UNDEFINED = 0;
275    /** Constant for {@link #navigationHidden}, value corresponding to the
276     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavAvailQualifier">navexposed</a>
277     * resource qualifier. */
278    public static final int NAVIGATIONHIDDEN_NO = 1;
279    /** Constant for {@link #navigationHidden}, value corresponding to the
280     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavAvailQualifier">navhidden</a>
281     * resource qualifier. */
282    public static final int NAVIGATIONHIDDEN_YES = 2;
283
284    /**
285     * A flag indicating whether any 5-way or DPAD navigation available.
286     * This will be set on a device with a mechanism to hide the navigation
287     * controls from the user, when that mechanism is closed.  One of:
288     * {@link #NAVIGATIONHIDDEN_NO}, {@link #NAVIGATIONHIDDEN_YES}.
289     */
290    public int navigationHidden;
291
292    /** Constant for {@link #orientation}: a value indicating that no value has been set. */
293    public static final int ORIENTATION_UNDEFINED = 0;
294    /** Constant for {@link #orientation}, value corresponding to the
295     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#OrientationQualifier">port</a>
296     * resource qualifier. */
297    public static final int ORIENTATION_PORTRAIT = 1;
298    /** Constant for {@link #orientation}, value corresponding to the
299     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#OrientationQualifier">land</a>
300     * resource qualifier. */
301    public static final int ORIENTATION_LANDSCAPE = 2;
302    /** @deprecated Not currently supported or used. */
303    @Deprecated public static final int ORIENTATION_SQUARE = 3;
304
305    /**
306     * Overall orientation of the screen.  May be one of
307     * {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}.
308     */
309    public int orientation;
310
311    /** Constant for {@link #uiMode}: bits that encode the mode type. */
312    public static final int UI_MODE_TYPE_MASK = 0x0f;
313    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
314     * value indicating that no mode type has been set. */
315    public static final int UI_MODE_TYPE_UNDEFINED = 0x00;
316    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
317     * value that corresponds to
318     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">no
319     * UI mode</a> resource qualifier specified. */
320    public static final int UI_MODE_TYPE_NORMAL = 0x01;
321    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
322     * value that corresponds to the
323     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">desk</a>
324     * resource qualifier. */
325    public static final int UI_MODE_TYPE_DESK = 0x02;
326    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
327     * value that corresponds to the
328     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">car</a>
329     * resource qualifier. */
330    public static final int UI_MODE_TYPE_CAR = 0x03;
331    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
332     * value that corresponds to the
333     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">television</a>
334     * resource qualifier. */
335    public static final int UI_MODE_TYPE_TELEVISION = 0x04;
336    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
337     * value that corresponds to the
338     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">appliance</a>
339     * resource qualifier. */
340    public static final int UI_MODE_TYPE_APPLIANCE = 0x05;
341
342    /** Constant for {@link #uiMode}: bits that encode the night mode. */
343    public static final int UI_MODE_NIGHT_MASK = 0x30;
344    /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK}
345     * value indicating that no mode type has been set. */
346    public static final int UI_MODE_NIGHT_UNDEFINED = 0x00;
347    /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK}
348     * value that corresponds to the
349     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NightQualifier">notnight</a>
350     * resource qualifier. */
351    public static final int UI_MODE_NIGHT_NO = 0x10;
352    /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK}
353     * value that corresponds to the
354     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NightQualifier">night</a>
355     * resource qualifier. */
356    public static final int UI_MODE_NIGHT_YES = 0x20;
357
358    /**
359     * Bit mask of the ui mode.  Currently there are two fields:
360     * <p>The {@link #UI_MODE_TYPE_MASK} bits define the overall ui mode of the
361     * device. They may be one of {@link #UI_MODE_TYPE_UNDEFINED},
362     * {@link #UI_MODE_TYPE_NORMAL}, {@link #UI_MODE_TYPE_DESK},
363     * {@link #UI_MODE_TYPE_CAR}, {@link #UI_MODE_TYPE_TELEVISION}, or
364     * {@link #UI_MODE_TYPE_APPLIANCE}.
365     *
366     * <p>The {@link #UI_MODE_NIGHT_MASK} defines whether the screen
367     * is in a special mode. They may be one of {@link #UI_MODE_NIGHT_UNDEFINED},
368     * {@link #UI_MODE_NIGHT_NO} or {@link #UI_MODE_NIGHT_YES}.
369     */
370    public int uiMode;
371
372    public static final int SCREEN_WIDTH_DP_UNDEFINED = 0;
373
374    /**
375     * The current width of the available screen space, in dp units,
376     * corresponding to
377     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenWidthQualifier">screen
378     * width</a> resource qualifier.
379     */
380    public int screenWidthDp;
381
382    public static final int SCREEN_HEIGHT_DP_UNDEFINED = 0;
383
384    /**
385     * The current height of the available screen space, in dp units,
386     * corresponding to
387     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenHeightQualifier">screen
388     * height</a> resource qualifier.
389     */
390    public int screenHeightDp;
391
392    public static final int SMALLEST_SCREEN_WIDTH_DP_UNDEFINED = 0;
393
394    /**
395     * The smallest screen size an application will see in normal operation,
396     * corresponding to
397     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#SmallestScreenWidthQualifier">smallest
398     * screen width</a> resource qualifier.
399     * This is the smallest value of both screenWidthDp and screenHeightDp
400     * in both portrait and landscape.
401     */
402    public int smallestScreenWidthDp;
403
404    /** @hide Hack to get this information from WM to app running in compat mode. */
405    public int compatScreenWidthDp;
406    /** @hide Hack to get this information from WM to app running in compat mode. */
407    public int compatScreenHeightDp;
408    /** @hide Hack to get this information from WM to app running in compat mode. */
409    public int compatSmallestScreenWidthDp;
410
411    /**
412     * @hide The layout direction associated to the current Locale
413     */
414    public int layoutDirection;
415
416    /**
417     * @hide Internal book-keeping.
418     */
419    public int seq;
420
421    /**
422     * Construct an invalid Configuration.  You must call {@link #setToDefaults}
423     * for this object to be valid.  {@more}
424     */
425    public Configuration() {
426        setToDefaults();
427    }
428
429    /**
430     * Makes a deep copy suitable for modification.
431     */
432    public Configuration(Configuration o) {
433        setTo(o);
434    }
435
436    public void setTo(Configuration o) {
437        fontScale = o.fontScale;
438        mcc = o.mcc;
439        mnc = o.mnc;
440        if (o.locale != null) {
441            locale = (Locale) o.locale.clone();
442            layoutDirection = o.layoutDirection;
443        }
444        userSetLocale = o.userSetLocale;
445        touchscreen = o.touchscreen;
446        keyboard = o.keyboard;
447        keyboardHidden = o.keyboardHidden;
448        hardKeyboardHidden = o.hardKeyboardHidden;
449        navigation = o.navigation;
450        navigationHidden = o.navigationHidden;
451        orientation = o.orientation;
452        screenLayout = o.screenLayout;
453        uiMode = o.uiMode;
454        screenWidthDp = o.screenWidthDp;
455        screenHeightDp = o.screenHeightDp;
456        smallestScreenWidthDp = o.smallestScreenWidthDp;
457        compatScreenWidthDp = o.compatScreenWidthDp;
458        compatScreenHeightDp = o.compatScreenHeightDp;
459        compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp;
460        seq = o.seq;
461    }
462
463    public String toString() {
464        StringBuilder sb = new StringBuilder(128);
465        sb.append("{");
466        sb.append(fontScale);
467        sb.append(" ");
468        sb.append(mcc);
469        sb.append("mcc");
470        sb.append(mnc);
471        sb.append("mnc");
472        if (locale != null) {
473            sb.append(" ");
474            sb.append(locale);
475        } else {
476            sb.append(" (no locale)");
477        }
478        switch (layoutDirection) {
479            case View.LAYOUT_DIRECTION_LTR: /* ltr not interesting */ break;
480            case View.LAYOUT_DIRECTION_RTL: sb.append(" rtl"); break;
481            default: sb.append(" layoutDir="); sb.append(layoutDirection); break;
482        }
483        if (smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
484            sb.append(" sw"); sb.append(smallestScreenWidthDp); sb.append("dp");
485        } else {
486            sb.append(" ?swdp");
487        }
488        if (screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) {
489            sb.append(" w"); sb.append(screenWidthDp); sb.append("dp");
490        } else {
491            sb.append(" ?wdp");
492        }
493        if (screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) {
494            sb.append(" h"); sb.append(screenHeightDp); sb.append("dp");
495        } else {
496            sb.append(" ?hdp");
497        }
498        switch ((screenLayout&SCREENLAYOUT_SIZE_MASK)) {
499            case SCREENLAYOUT_SIZE_UNDEFINED: sb.append(" ?lsize"); break;
500            case SCREENLAYOUT_SIZE_SMALL: sb.append(" smll"); break;
501            case SCREENLAYOUT_SIZE_NORMAL: sb.append(" nrml"); break;
502            case SCREENLAYOUT_SIZE_LARGE: sb.append(" lrg"); break;
503            case SCREENLAYOUT_SIZE_XLARGE: sb.append(" xlrg"); break;
504            default: sb.append(" layoutSize=");
505                    sb.append(screenLayout&SCREENLAYOUT_SIZE_MASK); break;
506        }
507        switch ((screenLayout&SCREENLAYOUT_LONG_MASK)) {
508            case SCREENLAYOUT_LONG_UNDEFINED: sb.append(" ?long"); break;
509            case SCREENLAYOUT_LONG_NO: /* not-long is not interesting to print */ break;
510            case SCREENLAYOUT_LONG_YES: sb.append(" long"); break;
511            default: sb.append(" layoutLong=");
512                    sb.append(screenLayout&SCREENLAYOUT_LONG_MASK); break;
513        }
514        switch (orientation) {
515            case ORIENTATION_UNDEFINED: sb.append(" ?orien"); break;
516            case ORIENTATION_LANDSCAPE: sb.append(" land"); break;
517            case ORIENTATION_PORTRAIT: sb.append(" port"); break;
518            default: sb.append(" orien="); sb.append(orientation); break;
519        }
520        switch ((uiMode&UI_MODE_TYPE_MASK)) {
521            case UI_MODE_TYPE_UNDEFINED: sb.append(" ?uimode"); break;
522            case UI_MODE_TYPE_NORMAL: /* normal is not interesting to print */ break;
523            case UI_MODE_TYPE_DESK: sb.append(" desk"); break;
524            case UI_MODE_TYPE_CAR: sb.append(" car"); break;
525            case UI_MODE_TYPE_TELEVISION: sb.append(" television"); break;
526            case UI_MODE_TYPE_APPLIANCE: sb.append(" appliance"); break;
527            default: sb.append(" uimode="); sb.append(uiMode&UI_MODE_TYPE_MASK); break;
528        }
529        switch ((uiMode&UI_MODE_NIGHT_MASK)) {
530            case UI_MODE_NIGHT_UNDEFINED: sb.append(" ?night"); break;
531            case UI_MODE_NIGHT_NO: /* not-night is not interesting to print */ break;
532            case UI_MODE_NIGHT_YES: sb.append(" night"); break;
533            default: sb.append(" night="); sb.append(uiMode&UI_MODE_NIGHT_MASK); break;
534        }
535        switch (touchscreen) {
536            case TOUCHSCREEN_UNDEFINED: sb.append(" ?touch"); break;
537            case TOUCHSCREEN_NOTOUCH: sb.append(" -touch"); break;
538            case TOUCHSCREEN_STYLUS: sb.append(" stylus"); break;
539            case TOUCHSCREEN_FINGER: sb.append(" finger"); break;
540            default: sb.append(" touch="); sb.append(touchscreen); break;
541        }
542        switch (keyboard) {
543            case KEYBOARD_UNDEFINED: sb.append(" ?keyb"); break;
544            case KEYBOARD_NOKEYS: sb.append(" -keyb"); break;
545            case KEYBOARD_QWERTY: sb.append(" qwerty"); break;
546            case KEYBOARD_12KEY: sb.append(" 12key"); break;
547            default: sb.append(" keys="); sb.append(keyboard); break;
548        }
549        switch (keyboardHidden) {
550            case KEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break;
551            case KEYBOARDHIDDEN_NO: sb.append("/v"); break;
552            case KEYBOARDHIDDEN_YES: sb.append("/h"); break;
553            case KEYBOARDHIDDEN_SOFT: sb.append("/s"); break;
554            default: sb.append("/"); sb.append(keyboardHidden); break;
555        }
556        switch (hardKeyboardHidden) {
557            case HARDKEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break;
558            case HARDKEYBOARDHIDDEN_NO: sb.append("/v"); break;
559            case HARDKEYBOARDHIDDEN_YES: sb.append("/h"); break;
560            default: sb.append("/"); sb.append(hardKeyboardHidden); break;
561        }
562        switch (navigation) {
563            case NAVIGATION_UNDEFINED: sb.append(" ?nav"); break;
564            case NAVIGATION_NONAV: sb.append(" -nav"); break;
565            case NAVIGATION_DPAD: sb.append(" dpad"); break;
566            case NAVIGATION_TRACKBALL: sb.append(" tball"); break;
567            case NAVIGATION_WHEEL: sb.append(" wheel"); break;
568            default: sb.append(" nav="); sb.append(navigation); break;
569        }
570        switch (navigationHidden) {
571            case NAVIGATIONHIDDEN_UNDEFINED: sb.append("/?"); break;
572            case NAVIGATIONHIDDEN_NO: sb.append("/v"); break;
573            case NAVIGATIONHIDDEN_YES: sb.append("/h"); break;
574            default: sb.append("/"); sb.append(navigationHidden); break;
575        }
576        if (seq != 0) {
577            sb.append(" s.");
578            sb.append(seq);
579        }
580        sb.append('}');
581        return sb.toString();
582    }
583
584    /**
585     * Set this object to the system defaults.
586     */
587    public void setToDefaults() {
588        fontScale = 1;
589        mcc = mnc = 0;
590        locale = null;
591        userSetLocale = false;
592        touchscreen = TOUCHSCREEN_UNDEFINED;
593        keyboard = KEYBOARD_UNDEFINED;
594        keyboardHidden = KEYBOARDHIDDEN_UNDEFINED;
595        hardKeyboardHidden = HARDKEYBOARDHIDDEN_UNDEFINED;
596        navigation = NAVIGATION_UNDEFINED;
597        navigationHidden = NAVIGATIONHIDDEN_UNDEFINED;
598        orientation = ORIENTATION_UNDEFINED;
599        screenLayout = SCREENLAYOUT_SIZE_UNDEFINED;
600        uiMode = UI_MODE_TYPE_UNDEFINED;
601        screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
602        screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
603        smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
604        layoutDirection = View.LAYOUT_DIRECTION_LTR;
605        seq = 0;
606    }
607
608    /** {@hide} */
609    @Deprecated public void makeDefault() {
610        setToDefaults();
611    }
612
613    /**
614     * Copy the fields from delta into this Configuration object, keeping
615     * track of which ones have changed.  Any undefined fields in
616     * <var>delta</var> are ignored and not copied in to the current
617     * Configuration.
618     * @return Returns a bit mask of the changed fields, as per
619     * {@link #diff}.
620     */
621    public int updateFrom(Configuration delta) {
622        int changed = 0;
623        if (delta.fontScale > 0 && fontScale != delta.fontScale) {
624            changed |= ActivityInfo.CONFIG_FONT_SCALE;
625            fontScale = delta.fontScale;
626        }
627        if (delta.mcc != 0 && mcc != delta.mcc) {
628            changed |= ActivityInfo.CONFIG_MCC;
629            mcc = delta.mcc;
630        }
631        if (delta.mnc != 0 && mnc != delta.mnc) {
632            changed |= ActivityInfo.CONFIG_MNC;
633            mnc = delta.mnc;
634        }
635        if (delta.locale != null
636                && (locale == null || !locale.equals(delta.locale))) {
637            changed |= ActivityInfo.CONFIG_LOCALE;
638            locale = delta.locale != null
639                    ? (Locale) delta.locale.clone() : null;
640            layoutDirection = LocaleUtil.getLayoutDirectionFromLocale(locale);
641        }
642        if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
643        {
644            userSetLocale = true;
645            changed |= ActivityInfo.CONFIG_LOCALE;
646        }
647        if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
648                && touchscreen != delta.touchscreen) {
649            changed |= ActivityInfo.CONFIG_TOUCHSCREEN;
650            touchscreen = delta.touchscreen;
651        }
652        if (delta.keyboard != KEYBOARD_UNDEFINED
653                && keyboard != delta.keyboard) {
654            changed |= ActivityInfo.CONFIG_KEYBOARD;
655            keyboard = delta.keyboard;
656        }
657        if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED
658                && keyboardHidden != delta.keyboardHidden) {
659            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
660            keyboardHidden = delta.keyboardHidden;
661        }
662        if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED
663                && hardKeyboardHidden != delta.hardKeyboardHidden) {
664            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
665            hardKeyboardHidden = delta.hardKeyboardHidden;
666        }
667        if (delta.navigation != NAVIGATION_UNDEFINED
668                && navigation != delta.navigation) {
669            changed |= ActivityInfo.CONFIG_NAVIGATION;
670            navigation = delta.navigation;
671        }
672        if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED
673                && navigationHidden != delta.navigationHidden) {
674            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
675            navigationHidden = delta.navigationHidden;
676        }
677        if (delta.orientation != ORIENTATION_UNDEFINED
678                && orientation != delta.orientation) {
679            changed |= ActivityInfo.CONFIG_ORIENTATION;
680            orientation = delta.orientation;
681        }
682        if (delta.screenLayout != SCREENLAYOUT_SIZE_UNDEFINED
683                && screenLayout != delta.screenLayout) {
684            changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
685            screenLayout = delta.screenLayout;
686        }
687        if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED)
688                && uiMode != delta.uiMode) {
689            changed |= ActivityInfo.CONFIG_UI_MODE;
690            if ((delta.uiMode&UI_MODE_TYPE_MASK) != UI_MODE_TYPE_UNDEFINED) {
691                uiMode = (uiMode&~UI_MODE_TYPE_MASK)
692                        | (delta.uiMode&UI_MODE_TYPE_MASK);
693            }
694            if ((delta.uiMode&UI_MODE_NIGHT_MASK) != UI_MODE_NIGHT_UNDEFINED) {
695                uiMode = (uiMode&~UI_MODE_NIGHT_MASK)
696                        | (delta.uiMode&UI_MODE_NIGHT_MASK);
697            }
698        }
699        if (delta.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED
700                && screenWidthDp != delta.screenWidthDp) {
701            changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
702            screenWidthDp = delta.screenWidthDp;
703        }
704        if (delta.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED
705                && screenHeightDp != delta.screenHeightDp) {
706            changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
707            screenHeightDp = delta.screenHeightDp;
708        }
709        if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
710            smallestScreenWidthDp = delta.smallestScreenWidthDp;
711        }
712        if (delta.compatScreenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) {
713            compatScreenWidthDp = delta.compatScreenWidthDp;
714        }
715        if (delta.compatScreenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) {
716            compatScreenHeightDp = delta.compatScreenHeightDp;
717        }
718        if (delta.compatSmallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
719            compatSmallestScreenWidthDp = delta.compatSmallestScreenWidthDp;
720        }
721
722        if (delta.seq != 0) {
723            seq = delta.seq;
724        }
725
726        return changed;
727    }
728
729    /**
730     * Return a bit mask of the differences between this Configuration
731     * object and the given one.  Does not change the values of either.  Any
732     * undefined fields in <var>delta</var> are ignored.
733     * @return Returns a bit mask indicating which configuration
734     * values has changed, containing any combination of
735     * {@link android.content.pm.ActivityInfo#CONFIG_FONT_SCALE
736     * PackageManager.ActivityInfo.CONFIG_FONT_SCALE},
737     * {@link android.content.pm.ActivityInfo#CONFIG_MCC
738     * PackageManager.ActivityInfo.CONFIG_MCC},
739     * {@link android.content.pm.ActivityInfo#CONFIG_MNC
740     * PackageManager.ActivityInfo.CONFIG_MNC},
741     * {@link android.content.pm.ActivityInfo#CONFIG_LOCALE
742     * PackageManager.ActivityInfo.CONFIG_LOCALE},
743     * {@link android.content.pm.ActivityInfo#CONFIG_TOUCHSCREEN
744     * PackageManager.ActivityInfo.CONFIG_TOUCHSCREEN},
745     * {@link android.content.pm.ActivityInfo#CONFIG_KEYBOARD
746     * PackageManager.ActivityInfo.CONFIG_KEYBOARD},
747     * {@link android.content.pm.ActivityInfo#CONFIG_NAVIGATION
748     * PackageManager.ActivityInfo.CONFIG_NAVIGATION},
749     * {@link android.content.pm.ActivityInfo#CONFIG_ORIENTATION
750     * PackageManager.ActivityInfo.CONFIG_ORIENTATION},
751     * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_LAYOUT
752     * PackageManager.ActivityInfo.CONFIG_SCREEN_LAYOUT}, or
753     * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_SIZE
754     * PackageManager.ActivityInfo.CONFIG_SCREEN_SIZE}, or
755     * {@link android.content.pm.ActivityInfo#CONFIG_SMALLEST_SCREEN_SIZE
756     * PackageManager.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE}.
757     */
758    public int diff(Configuration delta) {
759        int changed = 0;
760        if (delta.fontScale > 0 && fontScale != delta.fontScale) {
761            changed |= ActivityInfo.CONFIG_FONT_SCALE;
762        }
763        if (delta.mcc != 0 && mcc != delta.mcc) {
764            changed |= ActivityInfo.CONFIG_MCC;
765        }
766        if (delta.mnc != 0 && mnc != delta.mnc) {
767            changed |= ActivityInfo.CONFIG_MNC;
768        }
769        if (delta.locale != null
770                && (locale == null || !locale.equals(delta.locale))) {
771            changed |= ActivityInfo.CONFIG_LOCALE;
772        }
773        if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
774                && touchscreen != delta.touchscreen) {
775            changed |= ActivityInfo.CONFIG_TOUCHSCREEN;
776        }
777        if (delta.keyboard != KEYBOARD_UNDEFINED
778                && keyboard != delta.keyboard) {
779            changed |= ActivityInfo.CONFIG_KEYBOARD;
780        }
781        if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED
782                && keyboardHidden != delta.keyboardHidden) {
783            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
784        }
785        if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED
786                && hardKeyboardHidden != delta.hardKeyboardHidden) {
787            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
788        }
789        if (delta.navigation != NAVIGATION_UNDEFINED
790                && navigation != delta.navigation) {
791            changed |= ActivityInfo.CONFIG_NAVIGATION;
792        }
793        if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED
794                && navigationHidden != delta.navigationHidden) {
795            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
796        }
797        if (delta.orientation != ORIENTATION_UNDEFINED
798                && orientation != delta.orientation) {
799            changed |= ActivityInfo.CONFIG_ORIENTATION;
800        }
801        if (delta.screenLayout != SCREENLAYOUT_SIZE_UNDEFINED
802                && screenLayout != delta.screenLayout) {
803            changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
804        }
805        if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED)
806                && uiMode != delta.uiMode) {
807            changed |= ActivityInfo.CONFIG_UI_MODE;
808        }
809        if (delta.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED
810                && screenWidthDp != delta.screenWidthDp) {
811            changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
812        }
813        if (delta.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED
814                && screenHeightDp != delta.screenHeightDp) {
815            changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
816        }
817        if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
818                && smallestScreenWidthDp != delta.smallestScreenWidthDp) {
819            changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
820        }
821
822        return changed;
823    }
824
825    /**
826     * Determine if a new resource needs to be loaded from the bit set of
827     * configuration changes returned by {@link #updateFrom(Configuration)}.
828     *
829     * @param configChanges The mask of changes configurations as returned by
830     * {@link #updateFrom(Configuration)}.
831     * @param interestingChanges The configuration changes that the resource
832     * can handled, as given in {@link android.util.TypedValue#changingConfigurations}.
833     *
834     * @return Return true if the resource needs to be loaded, else false.
835     */
836    public static boolean needNewResources(int configChanges, int interestingChanges) {
837        return (configChanges & (interestingChanges|ActivityInfo.CONFIG_FONT_SCALE)) != 0;
838    }
839
840    /**
841     * @hide Return true if the sequence of 'other' is better than this.  Assumes
842     * that 'this' is your current sequence and 'other' is a new one you have
843     * received some how and want to compare with what you have.
844     */
845    public boolean isOtherSeqNewer(Configuration other) {
846        if (other == null) {
847            // Sanity check.
848            return false;
849        }
850        if (other.seq == 0) {
851            // If the other sequence is not specified, then we must assume
852            // it is newer since we don't know any better.
853            return true;
854        }
855        if (seq == 0) {
856            // If this sequence is not specified, then we also consider the
857            // other is better.  Yes we have a preference for other.  Sue us.
858            return true;
859        }
860        int diff = other.seq - seq;
861        if (diff > 0x10000) {
862            // If there has been a sufficiently large jump, assume the
863            // sequence has wrapped around.
864            return false;
865        }
866        return diff > 0;
867    }
868
869    /**
870     * Parcelable methods
871     */
872    public int describeContents() {
873        return 0;
874    }
875
876    public void writeToParcel(Parcel dest, int flags) {
877        dest.writeFloat(fontScale);
878        dest.writeInt(mcc);
879        dest.writeInt(mnc);
880        if (locale == null) {
881            dest.writeInt(0);
882        } else {
883            dest.writeInt(1);
884            dest.writeString(locale.getLanguage());
885            dest.writeString(locale.getCountry());
886            dest.writeString(locale.getVariant());
887        }
888        if(userSetLocale) {
889            dest.writeInt(1);
890        } else {
891            dest.writeInt(0);
892        }
893        dest.writeInt(touchscreen);
894        dest.writeInt(keyboard);
895        dest.writeInt(keyboardHidden);
896        dest.writeInt(hardKeyboardHidden);
897        dest.writeInt(navigation);
898        dest.writeInt(navigationHidden);
899        dest.writeInt(orientation);
900        dest.writeInt(screenLayout);
901        dest.writeInt(uiMode);
902        dest.writeInt(screenWidthDp);
903        dest.writeInt(screenHeightDp);
904        dest.writeInt(smallestScreenWidthDp);
905        dest.writeInt(compatScreenWidthDp);
906        dest.writeInt(compatScreenHeightDp);
907        dest.writeInt(compatSmallestScreenWidthDp);
908        dest.writeInt(layoutDirection);
909        dest.writeInt(seq);
910    }
911
912    public void readFromParcel(Parcel source) {
913        fontScale = source.readFloat();
914        mcc = source.readInt();
915        mnc = source.readInt();
916        if (source.readInt() != 0) {
917            locale = new Locale(source.readString(), source.readString(),
918                    source.readString());
919        }
920        userSetLocale = (source.readInt()==1);
921        touchscreen = source.readInt();
922        keyboard = source.readInt();
923        keyboardHidden = source.readInt();
924        hardKeyboardHidden = source.readInt();
925        navigation = source.readInt();
926        navigationHidden = source.readInt();
927        orientation = source.readInt();
928        screenLayout = source.readInt();
929        uiMode = source.readInt();
930        screenWidthDp = source.readInt();
931        screenHeightDp = source.readInt();
932        smallestScreenWidthDp = source.readInt();
933        compatScreenWidthDp = source.readInt();
934        compatScreenHeightDp = source.readInt();
935        compatSmallestScreenWidthDp = source.readInt();
936        layoutDirection = source.readInt();
937        seq = source.readInt();
938    }
939
940    public static final Parcelable.Creator<Configuration> CREATOR
941            = new Parcelable.Creator<Configuration>() {
942        public Configuration createFromParcel(Parcel source) {
943            return new Configuration(source);
944        }
945
946        public Configuration[] newArray(int size) {
947            return new Configuration[size];
948        }
949    };
950
951    /**
952     * Construct this Configuration object, reading from the Parcel.
953     */
954    private Configuration(Parcel source) {
955        readFromParcel(source);
956    }
957
958    public int compareTo(Configuration that) {
959        int n;
960        float a = this.fontScale;
961        float b = that.fontScale;
962        if (a < b) return -1;
963        if (a > b) return 1;
964        n = this.mcc - that.mcc;
965        if (n != 0) return n;
966        n = this.mnc - that.mnc;
967        if (n != 0) return n;
968        if (this.locale == null) {
969            if (that.locale != null) return 1;
970        } else if (that.locale == null) {
971            return -1;
972        } else {
973            n = this.locale.getLanguage().compareTo(that.locale.getLanguage());
974            if (n != 0) return n;
975            n = this.locale.getCountry().compareTo(that.locale.getCountry());
976            if (n != 0) return n;
977            n = this.locale.getVariant().compareTo(that.locale.getVariant());
978            if (n != 0) return n;
979        }
980        n = this.touchscreen - that.touchscreen;
981        if (n != 0) return n;
982        n = this.keyboard - that.keyboard;
983        if (n != 0) return n;
984        n = this.keyboardHidden - that.keyboardHidden;
985        if (n != 0) return n;
986        n = this.hardKeyboardHidden - that.hardKeyboardHidden;
987        if (n != 0) return n;
988        n = this.navigation - that.navigation;
989        if (n != 0) return n;
990        n = this.navigationHidden - that.navigationHidden;
991        if (n != 0) return n;
992        n = this.orientation - that.orientation;
993        if (n != 0) return n;
994        n = this.screenLayout - that.screenLayout;
995        if (n != 0) return n;
996        n = this.uiMode - that.uiMode;
997        if (n != 0) return n;
998        n = this.screenWidthDp - that.screenWidthDp;
999        if (n != 0) return n;
1000        n = this.screenHeightDp - that.screenHeightDp;
1001        if (n != 0) return n;
1002        n = this.smallestScreenWidthDp - that.smallestScreenWidthDp;
1003        //if (n != 0) return n;
1004        return n;
1005    }
1006
1007    public boolean equals(Configuration that) {
1008        if (that == null) return false;
1009        if (that == this) return true;
1010        return this.compareTo(that) == 0;
1011    }
1012
1013    public boolean equals(Object that) {
1014        try {
1015            return equals((Configuration)that);
1016        } catch (ClassCastException e) {
1017        }
1018        return false;
1019    }
1020
1021    public int hashCode() {
1022        int result = 17;
1023        result = 31 * result + Float.floatToIntBits(fontScale);
1024        result = 31 * result + mcc;
1025        result = 31 * result + mnc;
1026        result = 31 * result + (locale != null ? locale.hashCode() : 0);
1027        result = 31 * result + touchscreen;
1028        result = 31 * result + keyboard;
1029        result = 31 * result + keyboardHidden;
1030        result = 31 * result + hardKeyboardHidden;
1031        result = 31 * result + navigation;
1032        result = 31 * result + navigationHidden;
1033        result = 31 * result + orientation;
1034        result = 31 * result + screenLayout;
1035        result = 31 * result + uiMode;
1036        result = 31 * result + screenWidthDp;
1037        result = 31 * result + screenHeightDp;
1038        result = 31 * result + smallestScreenWidthDp;
1039        return result;
1040    }
1041}
1042