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