Home | History | Annotate | Download | only in res
      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 
     17 package android.content.res;
     18 
     19 import android.content.pm.ActivityInfo;
     20 import android.os.Parcel;
     21 import android.os.Parcelable;
     22 
     23 import java.util.Locale;
     24 
     25 /**
     26  * This class describes all device configuration information that can
     27  * impact the resources the application retrieves.  This includes both
     28  * user-specified configuration options (locale and scaling) as well
     29  * as dynamic device configuration (various types of input devices).
     30  */
     31 public final class Configuration implements Parcelable, Comparable<Configuration> {
     32     /**
     33      * Current user preference for the scaling factor for fonts, relative
     34      * to the base density scaling.
     35      */
     36     public float fontScale;
     37 
     38     /**
     39      * IMSI MCC (Mobile Country Code).  0 if undefined.
     40      */
     41     public int mcc;
     42 
     43     /**
     44      * IMSI MNC (Mobile Network Code).  0 if undefined.
     45      */
     46     public int mnc;
     47 
     48     /**
     49      * Current user preference for the locale.
     50      */
     51     public Locale locale;
     52 
     53     /**
     54      * Locale should persist on setting.  This is hidden because it is really
     55      * questionable whether this is the right way to expose the functionality.
     56      * @hide
     57      */
     58     public boolean userSetLocale;
     59 
     60     public static final int SCREENLAYOUT_SIZE_MASK = 0x0f;
     61     public static final int SCREENLAYOUT_SIZE_UNDEFINED = 0x00;
     62     public static final int SCREENLAYOUT_SIZE_SMALL = 0x01;
     63     public static final int SCREENLAYOUT_SIZE_NORMAL = 0x02;
     64     public static final int SCREENLAYOUT_SIZE_LARGE = 0x03;
     65 
     66     public static final int SCREENLAYOUT_LONG_MASK = 0x30;
     67     public static final int SCREENLAYOUT_LONG_UNDEFINED = 0x00;
     68     public static final int SCREENLAYOUT_LONG_NO = 0x10;
     69     public static final int SCREENLAYOUT_LONG_YES = 0x20;
     70 
     71     /**
     72      * Special flag we generate to indicate that the screen layout requires
     73      * us to use a compatibility mode for apps that are not modern layout
     74      * aware.
     75      * @hide
     76      */
     77     public static final int SCREENLAYOUT_COMPAT_NEEDED = 0x10000000;
     78 
     79     /**
     80      * Bit mask of overall layout of the screen.  Currently there are two
     81      * fields:
     82      * <p>The {@link #SCREENLAYOUT_SIZE_MASK} bits define the overall size
     83      * of the screen.  They may be one of
     84      * {@link #SCREENLAYOUT_SIZE_SMALL}, {@link #SCREENLAYOUT_SIZE_NORMAL},
     85      * or {@link #SCREENLAYOUT_SIZE_LARGE}.
     86      *
     87      * <p>The {@link #SCREENLAYOUT_LONG_MASK} defines whether the screen
     88      * is wider/taller than normal.  They may be one of
     89      * {@link #SCREENLAYOUT_LONG_NO} or {@link #SCREENLAYOUT_LONG_YES}.
     90      */
     91     public int screenLayout;
     92 
     93     public static final int TOUCHSCREEN_UNDEFINED = 0;
     94     public static final int TOUCHSCREEN_NOTOUCH = 1;
     95     public static final int TOUCHSCREEN_STYLUS = 2;
     96     public static final int TOUCHSCREEN_FINGER = 3;
     97 
     98     /**
     99      * The kind of touch screen attached to the device.
    100      * One of: {@link #TOUCHSCREEN_NOTOUCH}, {@link #TOUCHSCREEN_STYLUS},
    101      * {@link #TOUCHSCREEN_FINGER}.
    102      */
    103     public int touchscreen;
    104 
    105     public static final int KEYBOARD_UNDEFINED = 0;
    106     public static final int KEYBOARD_NOKEYS = 1;
    107     public static final int KEYBOARD_QWERTY = 2;
    108     public static final int KEYBOARD_12KEY = 3;
    109 
    110     /**
    111      * The kind of keyboard attached to the device.
    112      * One of: {@link #KEYBOARD_NOKEYS}, {@link #KEYBOARD_QWERTY},
    113      * {@link #KEYBOARD_12KEY}.
    114      */
    115     public int keyboard;
    116 
    117     public static final int KEYBOARDHIDDEN_UNDEFINED = 0;
    118     public static final int KEYBOARDHIDDEN_NO = 1;
    119     public static final int KEYBOARDHIDDEN_YES = 2;
    120     /** Constant matching actual resource implementation. {@hide} */
    121     public static final int KEYBOARDHIDDEN_SOFT = 3;
    122 
    123     /**
    124      * A flag indicating whether any keyboard is available.  Unlike
    125      * {@link #hardKeyboardHidden}, this also takes into account a soft
    126      * keyboard, so if the hard keyboard is hidden but there is soft
    127      * keyboard available, it will be set to NO.  Value is one of:
    128      * {@link #KEYBOARDHIDDEN_NO}, {@link #KEYBOARDHIDDEN_YES}.
    129      */
    130     public int keyboardHidden;
    131 
    132     public static final int HARDKEYBOARDHIDDEN_UNDEFINED = 0;
    133     public static final int HARDKEYBOARDHIDDEN_NO = 1;
    134     public static final int HARDKEYBOARDHIDDEN_YES = 2;
    135 
    136     /**
    137      * A flag indicating whether the hard keyboard has been hidden.  This will
    138      * be set on a device with a mechanism to hide the keyboard from the
    139      * user, when that mechanism is closed.  One of:
    140      * {@link #HARDKEYBOARDHIDDEN_NO}, {@link #HARDKEYBOARDHIDDEN_YES}.
    141      */
    142     public int hardKeyboardHidden;
    143 
    144     public static final int NAVIGATION_UNDEFINED = 0;
    145     public static final int NAVIGATION_NONAV = 1;
    146     public static final int NAVIGATION_DPAD = 2;
    147     public static final int NAVIGATION_TRACKBALL = 3;
    148     public static final int NAVIGATION_WHEEL = 4;
    149 
    150     /**
    151      * The kind of navigation method available on the device.
    152      * One of: {@link #NAVIGATION_NONAV}, {@link #NAVIGATION_DPAD},
    153      * {@link #NAVIGATION_TRACKBALL}, {@link #NAVIGATION_WHEEL}.
    154      */
    155     public int navigation;
    156 
    157     public static final int NAVIGATIONHIDDEN_UNDEFINED = 0;
    158     public static final int NAVIGATIONHIDDEN_NO = 1;
    159     public static final int NAVIGATIONHIDDEN_YES = 2;
    160 
    161     /**
    162      * A flag indicating whether any 5-way or DPAD navigation available.
    163      * This will be set on a device with a mechanism to hide the navigation
    164      * controls from the user, when that mechanism is closed.  One of:
    165      * {@link #NAVIGATIONHIDDEN_NO}, {@link #NAVIGATIONHIDDEN_YES}.
    166      */
    167     public int navigationHidden;
    168 
    169     public static final int ORIENTATION_UNDEFINED = 0;
    170     public static final int ORIENTATION_PORTRAIT = 1;
    171     public static final int ORIENTATION_LANDSCAPE = 2;
    172     public static final int ORIENTATION_SQUARE = 3;
    173 
    174     /**
    175      * Overall orientation of the screen.  May be one of
    176      * {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT},
    177      * or {@link #ORIENTATION_SQUARE}.
    178      */
    179     public int orientation;
    180 
    181     public static final int UI_MODE_TYPE_MASK = 0x0f;
    182     public static final int UI_MODE_TYPE_UNDEFINED = 0x00;
    183     public static final int UI_MODE_TYPE_NORMAL = 0x01;
    184     public static final int UI_MODE_TYPE_DESK = 0x02;
    185     public static final int UI_MODE_TYPE_CAR = 0x03;
    186 
    187     public static final int UI_MODE_NIGHT_MASK = 0x30;
    188     public static final int UI_MODE_NIGHT_UNDEFINED = 0x00;
    189     public static final int UI_MODE_NIGHT_NO = 0x10;
    190     public static final int UI_MODE_NIGHT_YES = 0x20;
    191 
    192     /**
    193      * Bit mask of the ui mode.  Currently there are two fields:
    194      * <p>The {@link #UI_MODE_TYPE_MASK} bits define the overall ui mode of the
    195      * device. They may be one of {@link #UI_MODE_TYPE_UNDEFINED},
    196      * {@link #UI_MODE_TYPE_NORMAL}, {@link #UI_MODE_TYPE_DESK},
    197      * or {@link #UI_MODE_TYPE_CAR}.
    198      *
    199      * <p>The {@link #UI_MODE_NIGHT_MASK} defines whether the screen
    200      * is in a special mode. They may be one of {@link #UI_MODE_NIGHT_UNDEFINED},
    201      * {@link #UI_MODE_NIGHT_NO} or {@link #UI_MODE_NIGHT_YES}.
    202      */
    203     public int uiMode;
    204 
    205     /**
    206      * @hide Internal book-keeping.
    207      */
    208     public int seq;
    209 
    210     /**
    211      * Construct an invalid Configuration.  You must call {@link #setToDefaults}
    212      * for this object to be valid.  {@more}
    213      */
    214     public Configuration() {
    215         setToDefaults();
    216     }
    217 
    218     /**
    219      * Makes a deep copy suitable for modification.
    220      */
    221     public Configuration(Configuration o) {
    222         setTo(o);
    223     }
    224 
    225     public void setTo(Configuration o) {
    226         fontScale = o.fontScale;
    227         mcc = o.mcc;
    228         mnc = o.mnc;
    229         if (o.locale != null) {
    230             locale = (Locale) o.locale.clone();
    231         }
    232         userSetLocale = o.userSetLocale;
    233         touchscreen = o.touchscreen;
    234         keyboard = o.keyboard;
    235         keyboardHidden = o.keyboardHidden;
    236         hardKeyboardHidden = o.hardKeyboardHidden;
    237         navigation = o.navigation;
    238         navigationHidden = o.navigationHidden;
    239         orientation = o.orientation;
    240         screenLayout = o.screenLayout;
    241         uiMode = o.uiMode;
    242         seq = o.seq;
    243     }
    244 
    245     public String toString() {
    246         StringBuilder sb = new StringBuilder(128);
    247         sb.append("{ scale=");
    248         sb.append(fontScale);
    249         sb.append(" imsi=");
    250         sb.append(mcc);
    251         sb.append("/");
    252         sb.append(mnc);
    253         sb.append(" loc=");
    254         sb.append(locale);
    255         sb.append(" touch=");
    256         sb.append(touchscreen);
    257         sb.append(" keys=");
    258         sb.append(keyboard);
    259         sb.append("/");
    260         sb.append(keyboardHidden);
    261         sb.append("/");
    262         sb.append(hardKeyboardHidden);
    263         sb.append(" nav=");
    264         sb.append(navigation);
    265         sb.append("/");
    266         sb.append(navigationHidden);
    267         sb.append(" orien=");
    268         sb.append(orientation);
    269         sb.append(" layout=");
    270         sb.append(screenLayout);
    271         sb.append(" uiMode=");
    272         sb.append(uiMode);
    273         if (seq != 0) {
    274             sb.append(" seq=");
    275             sb.append(seq);
    276         }
    277         sb.append('}');
    278         return sb.toString();
    279     }
    280 
    281     /**
    282      * Set this object to the system defaults.
    283      */
    284     public void setToDefaults() {
    285         fontScale = 1;
    286         mcc = mnc = 0;
    287         locale = null;
    288         userSetLocale = false;
    289         touchscreen = TOUCHSCREEN_UNDEFINED;
    290         keyboard = KEYBOARD_UNDEFINED;
    291         keyboardHidden = KEYBOARDHIDDEN_UNDEFINED;
    292         hardKeyboardHidden = HARDKEYBOARDHIDDEN_UNDEFINED;
    293         navigation = NAVIGATION_UNDEFINED;
    294         navigationHidden = NAVIGATIONHIDDEN_UNDEFINED;
    295         orientation = ORIENTATION_UNDEFINED;
    296         screenLayout = SCREENLAYOUT_SIZE_UNDEFINED;
    297         uiMode = UI_MODE_TYPE_UNDEFINED;
    298         seq = 0;
    299     }
    300 
    301     /** {@hide} */
    302     @Deprecated public void makeDefault() {
    303         setToDefaults();
    304     }
    305 
    306     /**
    307      * Copy the fields from delta into this Configuration object, keeping
    308      * track of which ones have changed.  Any undefined fields in
    309      * <var>delta</var> are ignored and not copied in to the current
    310      * Configuration.
    311      * @return Returns a bit mask of the changed fields, as per
    312      * {@link #diff}.
    313      */
    314     public int updateFrom(Configuration delta) {
    315         int changed = 0;
    316         if (delta.fontScale > 0 && fontScale != delta.fontScale) {
    317             changed |= ActivityInfo.CONFIG_FONT_SCALE;
    318             fontScale = delta.fontScale;
    319         }
    320         if (delta.mcc != 0 && mcc != delta.mcc) {
    321             changed |= ActivityInfo.CONFIG_MCC;
    322             mcc = delta.mcc;
    323         }
    324         if (delta.mnc != 0 && mnc != delta.mnc) {
    325             changed |= ActivityInfo.CONFIG_MNC;
    326             mnc = delta.mnc;
    327         }
    328         if (delta.locale != null
    329                 && (locale == null || !locale.equals(delta.locale))) {
    330             changed |= ActivityInfo.CONFIG_LOCALE;
    331             locale = delta.locale != null
    332                     ? (Locale) delta.locale.clone() : null;
    333         }
    334         if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
    335         {
    336             userSetLocale = true;
    337             changed |= ActivityInfo.CONFIG_LOCALE;
    338         }
    339         if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
    340                 && touchscreen != delta.touchscreen) {
    341             changed |= ActivityInfo.CONFIG_TOUCHSCREEN;
    342             touchscreen = delta.touchscreen;
    343         }
    344         if (delta.keyboard != KEYBOARD_UNDEFINED
    345                 && keyboard != delta.keyboard) {
    346             changed |= ActivityInfo.CONFIG_KEYBOARD;
    347             keyboard = delta.keyboard;
    348         }
    349         if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED
    350                 && keyboardHidden != delta.keyboardHidden) {
    351             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
    352             keyboardHidden = delta.keyboardHidden;
    353         }
    354         if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED
    355                 && hardKeyboardHidden != delta.hardKeyboardHidden) {
    356             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
    357             hardKeyboardHidden = delta.hardKeyboardHidden;
    358         }
    359         if (delta.navigation != NAVIGATION_UNDEFINED
    360                 && navigation != delta.navigation) {
    361             changed |= ActivityInfo.CONFIG_NAVIGATION;
    362             navigation = delta.navigation;
    363         }
    364         if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED
    365                 && navigationHidden != delta.navigationHidden) {
    366             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
    367             navigationHidden = delta.navigationHidden;
    368         }
    369         if (delta.orientation != ORIENTATION_UNDEFINED
    370                 && orientation != delta.orientation) {
    371             changed |= ActivityInfo.CONFIG_ORIENTATION;
    372             orientation = delta.orientation;
    373         }
    374         if (delta.screenLayout != SCREENLAYOUT_SIZE_UNDEFINED
    375                 && screenLayout != delta.screenLayout) {
    376             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
    377             screenLayout = delta.screenLayout;
    378         }
    379         if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED)
    380                 && uiMode != delta.uiMode) {
    381             changed |= ActivityInfo.CONFIG_UI_MODE;
    382             if ((delta.uiMode&UI_MODE_TYPE_MASK) != UI_MODE_TYPE_UNDEFINED) {
    383                 uiMode = (uiMode&~UI_MODE_TYPE_MASK)
    384                         | (delta.uiMode&UI_MODE_TYPE_MASK);
    385             }
    386             if ((delta.uiMode&UI_MODE_NIGHT_MASK) != UI_MODE_NIGHT_UNDEFINED) {
    387                 uiMode = (uiMode&~UI_MODE_NIGHT_MASK)
    388                         | (delta.uiMode&UI_MODE_NIGHT_MASK);
    389             }
    390         }
    391 
    392         if (delta.seq != 0) {
    393             seq = delta.seq;
    394         }
    395 
    396         return changed;
    397     }
    398 
    399     /**
    400      * Return a bit mask of the differences between this Configuration
    401      * object and the given one.  Does not change the values of either.  Any
    402      * undefined fields in <var>delta</var> are ignored.
    403      * @return Returns a bit mask indicating which configuration
    404      * values has changed, containing any combination of
    405      * {@link android.content.pm.ActivityInfo#CONFIG_FONT_SCALE
    406      * PackageManager.ActivityInfo.CONFIG_FONT_SCALE},
    407      * {@link android.content.pm.ActivityInfo#CONFIG_MCC
    408      * PackageManager.ActivityInfo.CONFIG_MCC},
    409      * {@link android.content.pm.ActivityInfo#CONFIG_MNC
    410      * PackageManager.ActivityInfo.CONFIG_MNC},
    411      * {@link android.content.pm.ActivityInfo#CONFIG_LOCALE
    412      * PackageManager.ActivityInfo.CONFIG_LOCALE},
    413      * {@link android.content.pm.ActivityInfo#CONFIG_TOUCHSCREEN
    414      * PackageManager.ActivityInfo.CONFIG_TOUCHSCREEN},
    415      * {@link android.content.pm.ActivityInfo#CONFIG_KEYBOARD
    416      * PackageManager.ActivityInfo.CONFIG_KEYBOARD},
    417      * {@link android.content.pm.ActivityInfo#CONFIG_NAVIGATION
    418      * PackageManager.ActivityInfo.CONFIG_NAVIGATION},
    419      * {@link android.content.pm.ActivityInfo#CONFIG_ORIENTATION
    420      * PackageManager.ActivityInfo.CONFIG_ORIENTATION}, or
    421      * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_LAYOUT
    422      * PackageManager.ActivityInfo.CONFIG_SCREEN_LAYOUT}.
    423      */
    424     public int diff(Configuration delta) {
    425         int changed = 0;
    426         if (delta.fontScale > 0 && fontScale != delta.fontScale) {
    427             changed |= ActivityInfo.CONFIG_FONT_SCALE;
    428         }
    429         if (delta.mcc != 0 && mcc != delta.mcc) {
    430             changed |= ActivityInfo.CONFIG_MCC;
    431         }
    432         if (delta.mnc != 0 && mnc != delta.mnc) {
    433             changed |= ActivityInfo.CONFIG_MNC;
    434         }
    435         if (delta.locale != null
    436                 && (locale == null || !locale.equals(delta.locale))) {
    437             changed |= ActivityInfo.CONFIG_LOCALE;
    438         }
    439         if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
    440                 && touchscreen != delta.touchscreen) {
    441             changed |= ActivityInfo.CONFIG_TOUCHSCREEN;
    442         }
    443         if (delta.keyboard != KEYBOARD_UNDEFINED
    444                 && keyboard != delta.keyboard) {
    445             changed |= ActivityInfo.CONFIG_KEYBOARD;
    446         }
    447         if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED
    448                 && keyboardHidden != delta.keyboardHidden) {
    449             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
    450         }
    451         if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED
    452                 && hardKeyboardHidden != delta.hardKeyboardHidden) {
    453             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
    454         }
    455         if (delta.navigation != NAVIGATION_UNDEFINED
    456                 && navigation != delta.navigation) {
    457             changed |= ActivityInfo.CONFIG_NAVIGATION;
    458         }
    459         if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED
    460                 && navigationHidden != delta.navigationHidden) {
    461             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
    462         }
    463         if (delta.orientation != ORIENTATION_UNDEFINED
    464                 && orientation != delta.orientation) {
    465             changed |= ActivityInfo.CONFIG_ORIENTATION;
    466         }
    467         if (delta.screenLayout != SCREENLAYOUT_SIZE_UNDEFINED
    468                 && screenLayout != delta.screenLayout) {
    469             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
    470         }
    471         if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED)
    472                 && uiMode != delta.uiMode) {
    473             changed |= ActivityInfo.CONFIG_UI_MODE;
    474         }
    475 
    476         return changed;
    477     }
    478 
    479     /**
    480      * Determine if a new resource needs to be loaded from the bit set of
    481      * configuration changes returned by {@link #updateFrom(Configuration)}.
    482      *
    483      * @param configChanges The mask of changes configurations as returned by
    484      * {@link #updateFrom(Configuration)}.
    485      * @param interestingChanges The configuration changes that the resource
    486      * can handled, as given in {@link android.util.TypedValue#changingConfigurations}.
    487      *
    488      * @return Return true if the resource needs to be loaded, else false.
    489      */
    490     public static boolean needNewResources(int configChanges, int interestingChanges) {
    491         return (configChanges & (interestingChanges|ActivityInfo.CONFIG_FONT_SCALE)) != 0;
    492     }
    493 
    494     /**
    495      * @hide Return true if the sequence of 'other' is better than this.  Assumes
    496      * that 'this' is your current sequence and 'other' is a new one you have
    497      * received some how and want to compare with what you have.
    498      */
    499     public boolean isOtherSeqNewer(Configuration other) {
    500         if (other == null) {
    501             // Sanity check.
    502             return false;
    503         }
    504         if (other.seq == 0) {
    505             // If the other sequence is not specified, then we must assume
    506             // it is newer since we don't know any better.
    507             return true;
    508         }
    509         if (seq == 0) {
    510             // If this sequence is not specified, then we also consider the
    511             // other is better.  Yes we have a preference for other.  Sue us.
    512             return true;
    513         }
    514         int diff = other.seq - seq;
    515         if (diff > 0x10000) {
    516             // If there has been a sufficiently large jump, assume the
    517             // sequence has wrapped around.
    518             return false;
    519         }
    520         return diff > 0;
    521     }
    522 
    523     /**
    524      * Parcelable methods
    525      */
    526     public int describeContents() {
    527         return 0;
    528     }
    529 
    530     public void writeToParcel(Parcel dest, int flags) {
    531         dest.writeFloat(fontScale);
    532         dest.writeInt(mcc);
    533         dest.writeInt(mnc);
    534         if (locale == null) {
    535             dest.writeInt(0);
    536         } else {
    537             dest.writeInt(1);
    538             dest.writeString(locale.getLanguage());
    539             dest.writeString(locale.getCountry());
    540             dest.writeString(locale.getVariant());
    541         }
    542         if(userSetLocale) {
    543             dest.writeInt(1);
    544         } else {
    545             dest.writeInt(0);
    546         }
    547         dest.writeInt(touchscreen);
    548         dest.writeInt(keyboard);
    549         dest.writeInt(keyboardHidden);
    550         dest.writeInt(hardKeyboardHidden);
    551         dest.writeInt(navigation);
    552         dest.writeInt(navigationHidden);
    553         dest.writeInt(orientation);
    554         dest.writeInt(screenLayout);
    555         dest.writeInt(uiMode);
    556         dest.writeInt(seq);
    557     }
    558 
    559     public void readFromParcel(Parcel source) {
    560         fontScale = source.readFloat();
    561         mcc = source.readInt();
    562         mnc = source.readInt();
    563         if (source.readInt() != 0) {
    564             locale = new Locale(source.readString(), source.readString(),
    565                     source.readString());
    566         }
    567         userSetLocale = (source.readInt()==1);
    568         touchscreen = source.readInt();
    569         keyboard = source.readInt();
    570         keyboardHidden = source.readInt();
    571         hardKeyboardHidden = source.readInt();
    572         navigation = source.readInt();
    573         navigationHidden = source.readInt();
    574         orientation = source.readInt();
    575         screenLayout = source.readInt();
    576         uiMode = source.readInt();
    577         seq = source.readInt();
    578     }
    579 
    580     public static final Parcelable.Creator<Configuration> CREATOR
    581             = new Parcelable.Creator<Configuration>() {
    582         public Configuration createFromParcel(Parcel source) {
    583             return new Configuration(source);
    584         }
    585 
    586         public Configuration[] newArray(int size) {
    587             return new Configuration[size];
    588         }
    589     };
    590 
    591     /**
    592      * Construct this Configuration object, reading from the Parcel.
    593      */
    594     private Configuration(Parcel source) {
    595         readFromParcel(source);
    596     }
    597 
    598     public int compareTo(Configuration that) {
    599         int n;
    600         float a = this.fontScale;
    601         float b = that.fontScale;
    602         if (a < b) return -1;
    603         if (a > b) return 1;
    604         n = this.mcc - that.mcc;
    605         if (n != 0) return n;
    606         n = this.mnc - that.mnc;
    607         if (n != 0) return n;
    608         if (this.locale == null) {
    609             if (that.locale != null) return 1;
    610         } else if (that.locale == null) {
    611             return -1;
    612         } else {
    613             n = this.locale.getLanguage().compareTo(that.locale.getLanguage());
    614             if (n != 0) return n;
    615             n = this.locale.getCountry().compareTo(that.locale.getCountry());
    616             if (n != 0) return n;
    617             n = this.locale.getVariant().compareTo(that.locale.getVariant());
    618             if (n != 0) return n;
    619         }
    620         n = this.touchscreen - that.touchscreen;
    621         if (n != 0) return n;
    622         n = this.keyboard - that.keyboard;
    623         if (n != 0) return n;
    624         n = this.keyboardHidden - that.keyboardHidden;
    625         if (n != 0) return n;
    626         n = this.hardKeyboardHidden - that.hardKeyboardHidden;
    627         if (n != 0) return n;
    628         n = this.navigation - that.navigation;
    629         if (n != 0) return n;
    630         n = this.navigationHidden - that.navigationHidden;
    631         if (n != 0) return n;
    632         n = this.orientation - that.orientation;
    633         if (n != 0) return n;
    634         n = this.screenLayout - that.screenLayout;
    635         if (n != 0) return n;
    636         n = this.uiMode - that.uiMode;
    637         //if (n != 0) return n;
    638         return n;
    639     }
    640 
    641     public boolean equals(Configuration that) {
    642         if (that == null) return false;
    643         if (that == this) return true;
    644         return this.compareTo(that) == 0;
    645     }
    646 
    647     public boolean equals(Object that) {
    648         try {
    649             return equals((Configuration)that);
    650         } catch (ClassCastException e) {
    651         }
    652         return false;
    653     }
    654 
    655     public int hashCode() {
    656         return ((int)this.fontScale) + this.mcc + this.mnc
    657                 + (this.locale != null ? this.locale.hashCode() : 0)
    658                 + this.touchscreen
    659                 + this.keyboard + this.keyboardHidden + this.hardKeyboardHidden
    660                 + this.navigation + this.navigationHidden
    661                 + this.orientation + this.screenLayout + this.uiMode;
    662     }
    663 }
    664