Configuration.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
1package android.content.res;
2
3import android.content.pm.ActivityInfo;
4import android.os.Parcel;
5import android.os.Parcelable;
6
7import java.util.Locale;
8
9/**
10 * This class describes all device configuration information that can
11 * impact the resources the application retrieves.  This includes both
12 * user-specified configuration options (locale and scaling) as well
13 * as dynamic device configuration (various types of input devices).
14 */
15public final class Configuration implements Parcelable, Comparable<Configuration> {
16    /**
17     * Current user preference for the scaling factor for fonts, relative
18     * to the base density scaling.
19     */
20    public float fontScale;
21
22    /**
23     * IMSI MCC (Mobile Country Code).  0 if undefined.
24     */
25    public int mcc;
26
27    /**
28     * IMSI MNC (Mobile Network Code).  0 if undefined.
29     */
30    public int mnc;
31
32    /**
33     * Current user preference for the locale.
34     */
35    public Locale locale;
36
37    public static final int TOUCHSCREEN_UNDEFINED = 0;
38    public static final int TOUCHSCREEN_NOTOUCH = 1;
39    public static final int TOUCHSCREEN_STYLUS = 2;
40    public static final int TOUCHSCREEN_FINGER = 3;
41
42    /**
43     * The kind of touch screen attached to the device.
44     * One of: {@link #TOUCHSCREEN_NOTOUCH}, {@link #TOUCHSCREEN_STYLUS},
45     * {@link #TOUCHSCREEN_FINGER}.
46     */
47    public int touchscreen;
48
49    public static final int KEYBOARD_UNDEFINED = 0;
50    public static final int KEYBOARD_NOKEYS = 1;
51    public static final int KEYBOARD_QWERTY = 2;
52    public static final int KEYBOARD_12KEY = 3;
53
54    /**
55     * The kind of keyboard attached to the device.
56     * One of: {@link #KEYBOARD_QWERTY}, {@link #KEYBOARD_12KEY}.
57     */
58    public int keyboard;
59
60    public static final int KEYBOARDHIDDEN_UNDEFINED = 0;
61    public static final int KEYBOARDHIDDEN_NO = 1;
62    public static final int KEYBOARDHIDDEN_YES = 2;
63
64    /**
65     * A flag indicating whether the keyboard has been hidden.  This will
66     * be set on a device with a mechanism to hide the keyboard from the
67     * user, when that mechanism is closed.
68     */
69    public int keyboardHidden;
70
71    public static final int NAVIGATION_UNDEFINED = 0;
72    public static final int NAVIGATION_NONAV = 1;
73    public static final int NAVIGATION_DPAD = 2;
74    public static final int NAVIGATION_TRACKBALL = 3;
75    public static final int NAVIGATION_WHEEL = 4;
76
77    /**
78     * The kind of navigation method available on the device.
79     * One of: {@link #NAVIGATION_DPAD}, {@link #NAVIGATION_TRACKBALL},
80     * {@link #NAVIGATION_WHEEL}.
81     */
82    public int navigation;
83
84    public static final int ORIENTATION_UNDEFINED = 0;
85    public static final int ORIENTATION_PORTRAIT = 1;
86    public static final int ORIENTATION_LANDSCAPE = 2;
87    public static final int ORIENTATION_SQUARE = 3;
88
89    /**
90     * Overall orientation of the screen.  May be one of
91     * {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT},
92     * or {@link #ORIENTATION_SQUARE}.
93     */
94    public int orientation;
95
96    /**
97     * Construct an invalid Configuration.  You must call {@link #setToDefaults}
98     * for this object to be valid.  {@more}
99     */
100    public Configuration() {
101        setToDefaults();
102    }
103
104    /**
105     * Makes a deep copy suitable for modification.
106     */
107    public Configuration(Configuration o) {
108        fontScale = o.fontScale;
109        mcc = o.mcc;
110        mnc = o.mnc;
111        if (o.locale != null) {
112            locale = (Locale) o.locale.clone();
113        }
114        touchscreen = o.touchscreen;
115        keyboard = o.keyboard;
116        keyboardHidden = o.keyboardHidden;
117        navigation = o.navigation;
118        orientation = o.orientation;
119    }
120
121    public String toString() {
122        return "{ scale=" + fontScale + " imsi=" + mcc + "/" + mnc
123                + " locale=" + locale
124                + " touch=" + touchscreen + " key=" + keyboard + "/"
125                + keyboardHidden
126                + " nav=" + navigation + " orien=" + orientation + " }";
127    }
128
129    /**
130     * Set this object to the system defaults.
131     */
132    public void setToDefaults() {
133        fontScale = 1;
134        mcc = mnc = 0;
135        locale = Locale.getDefault();
136        touchscreen = TOUCHSCREEN_UNDEFINED;
137        keyboard = KEYBOARD_UNDEFINED;
138        keyboardHidden = KEYBOARDHIDDEN_UNDEFINED;
139        navigation = NAVIGATION_UNDEFINED;
140        orientation = ORIENTATION_UNDEFINED;
141    }
142
143    /** {@hide} */
144    @Deprecated public void makeDefault() {
145        setToDefaults();
146    }
147
148    /**
149     * Copy the fields from delta into this Configuration object, keeping
150     * track of which ones have changed.  Any undefined fields in
151     * <var>delta</var> are ignored and not copied in to the current
152     * Configuration.
153     * @return Returns a bit mask of the changed fields, as per
154     * {@link #diff}.
155     */
156    public int updateFrom(Configuration delta) {
157        int changed = 0;
158        if (delta.fontScale > 0 && fontScale != delta.fontScale) {
159            changed |= ActivityInfo.CONFIG_FONT_SCALE;
160            fontScale = delta.fontScale;
161        }
162        if (delta.mcc != 0 && mcc != delta.mcc) {
163            changed |= ActivityInfo.CONFIG_MCC;
164            mcc = delta.mcc;
165        }
166        if (delta.mnc != 0 && mnc != delta.mnc) {
167            changed |= ActivityInfo.CONFIG_MNC;
168            mnc = delta.mnc;
169        }
170        if (delta.locale != null
171                && (locale == null || !locale.equals(delta.locale))) {
172            changed |= ActivityInfo.CONFIG_LOCALE;
173            locale = delta.locale != null
174                    ? (Locale) delta.locale.clone() : null;
175        }
176        if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
177                && touchscreen != delta.touchscreen) {
178            changed |= ActivityInfo.CONFIG_TOUCHSCREEN;
179            touchscreen = delta.touchscreen;
180        }
181        if (delta.keyboard != KEYBOARD_UNDEFINED
182                && keyboard != delta.keyboard) {
183            changed |= ActivityInfo.CONFIG_KEYBOARD;
184            keyboard = delta.keyboard;
185        }
186        if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED
187                && keyboardHidden != delta.keyboardHidden) {
188            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
189            keyboardHidden = delta.keyboardHidden;
190        }
191        if (delta.navigation != NAVIGATION_UNDEFINED
192                && navigation != delta.navigation) {
193            changed |= ActivityInfo.CONFIG_NAVIGATION;
194            navigation = delta.navigation;
195        }
196        if (delta.orientation != ORIENTATION_UNDEFINED
197                && orientation != delta.orientation) {
198            changed |= ActivityInfo.CONFIG_ORIENTATION;
199            orientation = delta.orientation;
200        }
201
202        return changed;
203    }
204
205    /**
206     * Return a bit mask of the differences between this Configuration
207     * object and the given one.  Does not change the values of either.  Any
208     * undefined fields in <var>delta</var> are ignored.
209     * @return Returns a bit mask indicating which configuration
210     * values has changed, containing any combination of
211     * {@link android.content.pm.ActivityInfo#CONFIG_FONT_SCALE
212     * PackageManager.ActivityInfo.CONFIG_FONT_SCALE},
213     * {@link android.content.pm.ActivityInfo#CONFIG_MCC
214     * PackageManager.ActivityInfo.CONFIG_MCC},
215     * {@link android.content.pm.ActivityInfo#CONFIG_MNC
216     * PackageManager.ActivityInfo.CONFIG_MNC},
217     * {@link android.content.pm.ActivityInfo#CONFIG_LOCALE
218     * PackageManager.ActivityInfo.CONFIG_LOCALE},
219     * {@link android.content.pm.ActivityInfo#CONFIG_TOUCHSCREEN
220     * PackageManager.ActivityInfo.CONFIG_TOUCHSCREEN},
221     * {@link android.content.pm.ActivityInfo#CONFIG_KEYBOARD
222     * PackageManager.ActivityInfo.CONFIG_KEYBOARD},
223     * {@link android.content.pm.ActivityInfo#CONFIG_NAVIGATION
224     * PackageManager.ActivityInfo.CONFIG_NAVIGATION}, or
225     * {@link android.content.pm.ActivityInfo#CONFIG_ORIENTATION
226     * PackageManager.ActivityInfo.CONFIG_ORIENTATION}.
227     */
228    public int diff(Configuration delta) {
229        int changed = 0;
230        if (delta.fontScale > 0 && fontScale != delta.fontScale) {
231            changed |= ActivityInfo.CONFIG_FONT_SCALE;
232        }
233        if (delta.mcc != 0 && mcc != delta.mcc) {
234            changed |= ActivityInfo.CONFIG_MCC;
235        }
236        if (delta.mnc != 0 && mnc != delta.mnc) {
237            changed |= ActivityInfo.CONFIG_MNC;
238        }
239        if (delta.locale != null
240                && (locale == null || !locale.equals(delta.locale))) {
241            changed |= ActivityInfo.CONFIG_LOCALE;
242        }
243        if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
244                && touchscreen != delta.touchscreen) {
245            changed |= ActivityInfo.CONFIG_TOUCHSCREEN;
246        }
247        if (delta.keyboard != KEYBOARD_UNDEFINED
248                && keyboard != delta.keyboard) {
249            changed |= ActivityInfo.CONFIG_KEYBOARD;
250        }
251        if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED
252                && keyboardHidden != delta.keyboardHidden) {
253            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
254        }
255        if (delta.navigation != NAVIGATION_UNDEFINED
256                && navigation != delta.navigation) {
257            changed |= ActivityInfo.CONFIG_NAVIGATION;
258        }
259        if (delta.orientation != ORIENTATION_UNDEFINED
260                && orientation != delta.orientation) {
261            changed |= ActivityInfo.CONFIG_ORIENTATION;
262        }
263
264        return changed;
265    }
266
267    /**
268     * Determine if a new resource needs to be loaded from the bit set of
269     * configuration changes returned by {@link #updateFrom(Configuration)}.
270     *
271     * @param configChanges The mask of changes configurations as returned by
272     * {@link #updateFrom(Configuration)}.
273     * @param interestingChanges The configuration changes that the resource
274     * can handled, as given in {@link android.util.TypedValue#changingConfigurations}.
275     *
276     * @return Return true if the resource needs to be loaded, else false.
277     */
278    public static boolean needNewResources(int configChanges, int interestingChanges) {
279        return (configChanges & (interestingChanges|ActivityInfo.CONFIG_FONT_SCALE)) != 0;
280    }
281
282    /**
283     * Parcelable methods
284     */
285    public int describeContents() {
286        return 0;
287    }
288
289    public void writeToParcel(Parcel dest, int flags) {
290        dest.writeFloat(fontScale);
291        dest.writeInt(mcc);
292        dest.writeInt(mnc);
293        if (locale == null) {
294            dest.writeInt(0);
295        } else {
296            dest.writeInt(1);
297            dest.writeString(locale.getLanguage());
298            dest.writeString(locale.getCountry());
299            dest.writeString(locale.getVariant());
300        }
301        dest.writeInt(touchscreen);
302        dest.writeInt(keyboard);
303        dest.writeInt(keyboardHidden);
304        dest.writeInt(navigation);
305        dest.writeInt(orientation);
306    }
307
308    public static final Parcelable.Creator<Configuration> CREATOR
309            = new Parcelable.Creator<Configuration>() {
310        public Configuration createFromParcel(Parcel source) {
311            return new Configuration(source);
312        }
313
314        public Configuration[] newArray(int size) {
315            return new Configuration[size];
316        }
317    };
318
319    /**
320     * Construct this Configuration object, reading from the Parcel.
321     */
322    private Configuration(Parcel source) {
323        fontScale = source.readFloat();
324        mcc = source.readInt();
325        mnc = source.readInt();
326        if (source.readInt() != 0) {
327            locale = new Locale(source.readString(), source.readString(),
328                    source.readString());
329        }
330        touchscreen = source.readInt();
331        keyboard = source.readInt();
332        keyboardHidden = source.readInt();
333        navigation = source.readInt();
334        orientation = source.readInt();
335    }
336
337    public int compareTo(Configuration that) {
338        int n;
339        float a = this.fontScale;
340        float b = that.fontScale;
341        if (a < b) return -1;
342        if (a > b) return 1;
343        n = this.mcc - that.mcc;
344        if (n != 0) return n;
345        n = this.mnc - that.mnc;
346        if (n != 0) return n;
347        n = this.locale.getLanguage().compareTo(that.locale.getLanguage());
348        if (n != 0) return n;
349        n = this.locale.getCountry().compareTo(that.locale.getCountry());
350        if (n != 0) return n;
351        n = this.locale.getVariant().compareTo(that.locale.getVariant());
352        if (n != 0) return n;
353        n = this.touchscreen - that.touchscreen;
354        if (n != 0) return n;
355        n = this.keyboard - that.keyboard;
356        if (n != 0) return n;
357        n = this.keyboardHidden - that.keyboardHidden;
358        if (n != 0) return n;
359        n = this.navigation - that.navigation;
360        if (n != 0) return n;
361        n = this.orientation - that.orientation;
362        //if (n != 0) return n;
363        return n;
364    }
365
366    public boolean equals(Configuration that) {
367        if (that == null) return false;
368        if (that == this) return true;
369        return this.compareTo(that) == 0;
370    }
371
372    public boolean equals(Object that) {
373        try {
374            return equals((Configuration)that);
375        } catch (ClassCastException e) {
376        }
377        return false;
378    }
379
380    public int hashCode() {
381        return ((int)this.fontScale) + this.mcc + this.mnc
382                + this.locale.hashCode() + this.touchscreen
383                + this.keyboard + this.keyboardHidden + this.navigation
384                + this.orientation;
385    }
386}