Configuration.java revision c4db95c077f826585d20be2f3db4043c53d30cf5
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 /** 38 * Locale should persist on setting. This is hidden because it is really 39 * questionable whether this is the right way to expose the functionality. 40 * @hide 41 */ 42 public boolean userSetLocale; 43 44 public static final int SCREENLAYOUT_SIZE_MASK = 0x0f; 45 public static final int SCREENLAYOUT_SIZE_UNDEFINED = 0x00; 46 public static final int SCREENLAYOUT_SIZE_SMALL = 0x01; 47 public static final int SCREENLAYOUT_SIZE_NORMAL = 0x02; 48 public static final int SCREENLAYOUT_SIZE_LARGE = 0x03; 49 50 public static final int SCREENLAYOUT_LONG_MASK = 0x30; 51 public static final int SCREENLAYOUT_LONG_UNDEFINED = 0x00; 52 public static final int SCREENLAYOUT_LONG_NO = 0x10; 53 public static final int SCREENLAYOUT_LONG_YES = 0x20; 54 55 /** 56 * Special flag we generate to indicate that the screen layout requires 57 * us to use a compatibility mode for apps that are not modern layout 58 * aware. 59 * @hide 60 */ 61 public static final int SCREENLAYOUT_COMPAT_NEEDED = 0x10000000; 62 63 /** 64 * Bit mask of overall layout of the screen. Currently there are two 65 * fields: 66 * <p>The {@link #SCREENLAYOUT_SIZE_MASK} bits define the overall size 67 * of the screen. They may be one of 68 * {@link #SCREENLAYOUT_SIZE_SMALL}, {@link #SCREENLAYOUT_SIZE_NORMAL}, 69 * or {@link #SCREENLAYOUT_SIZE_LARGE}. 70 * 71 * <p>The {@link #SCREENLAYOUT_LONG_MASK} defines whether the screen 72 * is wider/taller than normal. They may be one of 73 * {@link #SCREENLAYOUT_LONG_NO} or {@link #SCREENLAYOUT_LONG_YES}. 74 */ 75 public int screenLayout; 76 77 public static final int TOUCHSCREEN_UNDEFINED = 0; 78 public static final int TOUCHSCREEN_NOTOUCH = 1; 79 public static final int TOUCHSCREEN_STYLUS = 2; 80 public static final int TOUCHSCREEN_FINGER = 3; 81 82 /** 83 * The kind of touch screen attached to the device. 84 * One of: {@link #TOUCHSCREEN_NOTOUCH}, {@link #TOUCHSCREEN_STYLUS}, 85 * {@link #TOUCHSCREEN_FINGER}. 86 */ 87 public int touchscreen; 88 89 public static final int KEYBOARD_UNDEFINED = 0; 90 public static final int KEYBOARD_NOKEYS = 1; 91 public static final int KEYBOARD_QWERTY = 2; 92 public static final int KEYBOARD_12KEY = 3; 93 94 /** 95 * The kind of keyboard attached to the device. 96 * One of: {@link #KEYBOARD_QWERTY}, {@link #KEYBOARD_12KEY}. 97 */ 98 public int keyboard; 99 100 public static final int KEYBOARDHIDDEN_UNDEFINED = 0; 101 public static final int KEYBOARDHIDDEN_NO = 1; 102 public static final int KEYBOARDHIDDEN_YES = 2; 103 /** Constant matching actual resource implementation. {@hide} */ 104 public static final int KEYBOARDHIDDEN_SOFT = 3; 105 106 /** 107 * A flag indicating whether any keyboard is available. Unlike 108 * {@link #hardKeyboardHidden}, this also takes into account a soft 109 * keyboard, so if the hard keyboard is hidden but there is soft 110 * keyboard available, it will be set to NO. Value is one of: 111 * {@link #KEYBOARDHIDDEN_NO}, {@link #KEYBOARDHIDDEN_YES}. 112 */ 113 public int keyboardHidden; 114 115 public static final int HARDKEYBOARDHIDDEN_UNDEFINED = 0; 116 public static final int HARDKEYBOARDHIDDEN_NO = 1; 117 public static final int HARDKEYBOARDHIDDEN_YES = 2; 118 119 /** 120 * A flag indicating whether the hard keyboard has been hidden. This will 121 * be set on a device with a mechanism to hide the keyboard from the 122 * user, when that mechanism is closed. One of: 123 * {@link #HARDKEYBOARDHIDDEN_NO}, {@link #HARDKEYBOARDHIDDEN_YES}. 124 */ 125 public int hardKeyboardHidden; 126 127 public static final int NAVIGATION_UNDEFINED = 0; 128 public static final int NAVIGATION_NONAV = 1; 129 public static final int NAVIGATION_DPAD = 2; 130 public static final int NAVIGATION_TRACKBALL = 3; 131 public static final int NAVIGATION_WHEEL = 4; 132 133 /** 134 * The kind of navigation method available on the device. 135 * One of: {@link #NAVIGATION_DPAD}, {@link #NAVIGATION_TRACKBALL}, 136 * {@link #NAVIGATION_WHEEL}. 137 */ 138 public int navigation; 139 140 public static final int ORIENTATION_UNDEFINED = 0; 141 public static final int ORIENTATION_PORTRAIT = 1; 142 public static final int ORIENTATION_LANDSCAPE = 2; 143 public static final int ORIENTATION_SQUARE = 3; 144 145 /** 146 * Overall orientation of the screen. May be one of 147 * {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}, 148 * or {@link #ORIENTATION_SQUARE}. 149 */ 150 public int orientation; 151 152 /** 153 * Construct an invalid Configuration. You must call {@link #setToDefaults} 154 * for this object to be valid. {@more} 155 */ 156 public Configuration() { 157 setToDefaults(); 158 } 159 160 /** 161 * Makes a deep copy suitable for modification. 162 */ 163 public Configuration(Configuration o) { 164 fontScale = o.fontScale; 165 mcc = o.mcc; 166 mnc = o.mnc; 167 if (o.locale != null) { 168 locale = (Locale) o.locale.clone(); 169 } 170 userSetLocale = o.userSetLocale; 171 touchscreen = o.touchscreen; 172 keyboard = o.keyboard; 173 keyboardHidden = o.keyboardHidden; 174 hardKeyboardHidden = o.hardKeyboardHidden; 175 navigation = o.navigation; 176 orientation = o.orientation; 177 screenLayout = o.screenLayout; 178 } 179 180 public String toString() { 181 StringBuilder sb = new StringBuilder(128); 182 sb.append("{ scale="); 183 sb.append(fontScale); 184 sb.append(" imsi="); 185 sb.append(mcc); 186 sb.append("/"); 187 sb.append(mnc); 188 sb.append(" loc="); 189 sb.append(locale); 190 sb.append(" touch="); 191 sb.append(touchscreen); 192 sb.append(" keys="); 193 sb.append(keyboard); 194 sb.append("/"); 195 sb.append(keyboardHidden); 196 sb.append("/"); 197 sb.append(hardKeyboardHidden); 198 sb.append(" nav="); 199 sb.append(navigation); 200 sb.append(" orien="); 201 sb.append(orientation); 202 sb.append(" layout="); 203 sb.append(screenLayout); 204 sb.append('}'); 205 return sb.toString(); 206 } 207 208 /** 209 * Set this object to the system defaults. 210 */ 211 public void setToDefaults() { 212 fontScale = 1; 213 mcc = mnc = 0; 214 locale = Locale.getDefault(); 215 userSetLocale = false; 216 touchscreen = TOUCHSCREEN_UNDEFINED; 217 keyboard = KEYBOARD_UNDEFINED; 218 keyboardHidden = KEYBOARDHIDDEN_UNDEFINED; 219 hardKeyboardHidden = HARDKEYBOARDHIDDEN_UNDEFINED; 220 navigation = NAVIGATION_UNDEFINED; 221 orientation = ORIENTATION_UNDEFINED; 222 screenLayout = SCREENLAYOUT_SIZE_UNDEFINED; 223 } 224 225 /** {@hide} */ 226 @Deprecated public void makeDefault() { 227 setToDefaults(); 228 } 229 230 /** 231 * Copy the fields from delta into this Configuration object, keeping 232 * track of which ones have changed. Any undefined fields in 233 * <var>delta</var> are ignored and not copied in to the current 234 * Configuration. 235 * @return Returns a bit mask of the changed fields, as per 236 * {@link #diff}. 237 */ 238 public int updateFrom(Configuration delta) { 239 int changed = 0; 240 if (delta.fontScale > 0 && fontScale != delta.fontScale) { 241 changed |= ActivityInfo.CONFIG_FONT_SCALE; 242 fontScale = delta.fontScale; 243 } 244 if (delta.mcc != 0 && mcc != delta.mcc) { 245 changed |= ActivityInfo.CONFIG_MCC; 246 mcc = delta.mcc; 247 } 248 if (delta.mnc != 0 && mnc != delta.mnc) { 249 changed |= ActivityInfo.CONFIG_MNC; 250 mnc = delta.mnc; 251 } 252 if (delta.locale != null 253 && (locale == null || !locale.equals(delta.locale))) { 254 changed |= ActivityInfo.CONFIG_LOCALE; 255 locale = delta.locale != null 256 ? (Locale) delta.locale.clone() : null; 257 } 258 if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0))) 259 { 260 userSetLocale = true; 261 changed |= ActivityInfo.CONFIG_LOCALE; 262 } 263 if (delta.touchscreen != TOUCHSCREEN_UNDEFINED 264 && touchscreen != delta.touchscreen) { 265 changed |= ActivityInfo.CONFIG_TOUCHSCREEN; 266 touchscreen = delta.touchscreen; 267 } 268 if (delta.keyboard != KEYBOARD_UNDEFINED 269 && keyboard != delta.keyboard) { 270 changed |= ActivityInfo.CONFIG_KEYBOARD; 271 keyboard = delta.keyboard; 272 } 273 if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED 274 && keyboardHidden != delta.keyboardHidden) { 275 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 276 keyboardHidden = delta.keyboardHidden; 277 } 278 if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED 279 && hardKeyboardHidden != delta.hardKeyboardHidden) { 280 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 281 hardKeyboardHidden = delta.hardKeyboardHidden; 282 } 283 if (delta.navigation != NAVIGATION_UNDEFINED 284 && navigation != delta.navigation) { 285 changed |= ActivityInfo.CONFIG_NAVIGATION; 286 navigation = delta.navigation; 287 } 288 if (delta.orientation != ORIENTATION_UNDEFINED 289 && orientation != delta.orientation) { 290 changed |= ActivityInfo.CONFIG_ORIENTATION; 291 orientation = delta.orientation; 292 } 293 if (delta.screenLayout != SCREENLAYOUT_SIZE_UNDEFINED 294 && screenLayout != delta.screenLayout) { 295 changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; 296 screenLayout = delta.screenLayout; 297 } 298 299 return changed; 300 } 301 302 /** 303 * Return a bit mask of the differences between this Configuration 304 * object and the given one. Does not change the values of either. Any 305 * undefined fields in <var>delta</var> are ignored. 306 * @return Returns a bit mask indicating which configuration 307 * values has changed, containing any combination of 308 * {@link android.content.pm.ActivityInfo#CONFIG_FONT_SCALE 309 * PackageManager.ActivityInfo.CONFIG_FONT_SCALE}, 310 * {@link android.content.pm.ActivityInfo#CONFIG_MCC 311 * PackageManager.ActivityInfo.CONFIG_MCC}, 312 * {@link android.content.pm.ActivityInfo#CONFIG_MNC 313 * PackageManager.ActivityInfo.CONFIG_MNC}, 314 * {@link android.content.pm.ActivityInfo#CONFIG_LOCALE 315 * PackageManager.ActivityInfo.CONFIG_LOCALE}, 316 * {@link android.content.pm.ActivityInfo#CONFIG_TOUCHSCREEN 317 * PackageManager.ActivityInfo.CONFIG_TOUCHSCREEN}, 318 * {@link android.content.pm.ActivityInfo#CONFIG_KEYBOARD 319 * PackageManager.ActivityInfo.CONFIG_KEYBOARD}, 320 * {@link android.content.pm.ActivityInfo#CONFIG_NAVIGATION 321 * PackageManager.ActivityInfo.CONFIG_NAVIGATION}, 322 * {@link android.content.pm.ActivityInfo#CONFIG_ORIENTATION 323 * PackageManager.ActivityInfo.CONFIG_ORIENTATION}, or 324 * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_LAYOUT 325 * PackageManager.ActivityInfo.CONFIG_SCREEN_LAYOUT}. 326 */ 327 public int diff(Configuration delta) { 328 int changed = 0; 329 if (delta.fontScale > 0 && fontScale != delta.fontScale) { 330 changed |= ActivityInfo.CONFIG_FONT_SCALE; 331 } 332 if (delta.mcc != 0 && mcc != delta.mcc) { 333 changed |= ActivityInfo.CONFIG_MCC; 334 } 335 if (delta.mnc != 0 && mnc != delta.mnc) { 336 changed |= ActivityInfo.CONFIG_MNC; 337 } 338 if (delta.locale != null 339 && (locale == null || !locale.equals(delta.locale))) { 340 changed |= ActivityInfo.CONFIG_LOCALE; 341 } 342 if (delta.touchscreen != TOUCHSCREEN_UNDEFINED 343 && touchscreen != delta.touchscreen) { 344 changed |= ActivityInfo.CONFIG_TOUCHSCREEN; 345 } 346 if (delta.keyboard != KEYBOARD_UNDEFINED 347 && keyboard != delta.keyboard) { 348 changed |= ActivityInfo.CONFIG_KEYBOARD; 349 } 350 if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED 351 && keyboardHidden != delta.keyboardHidden) { 352 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 353 } 354 if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED 355 && hardKeyboardHidden != delta.hardKeyboardHidden) { 356 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 357 } 358 if (delta.navigation != NAVIGATION_UNDEFINED 359 && navigation != delta.navigation) { 360 changed |= ActivityInfo.CONFIG_NAVIGATION; 361 } 362 if (delta.orientation != ORIENTATION_UNDEFINED 363 && orientation != delta.orientation) { 364 changed |= ActivityInfo.CONFIG_ORIENTATION; 365 } 366 if (delta.screenLayout != SCREENLAYOUT_SIZE_UNDEFINED 367 && screenLayout != delta.screenLayout) { 368 changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; 369 } 370 371 return changed; 372 } 373 374 /** 375 * Determine if a new resource needs to be loaded from the bit set of 376 * configuration changes returned by {@link #updateFrom(Configuration)}. 377 * 378 * @param configChanges The mask of changes configurations as returned by 379 * {@link #updateFrom(Configuration)}. 380 * @param interestingChanges The configuration changes that the resource 381 * can handled, as given in {@link android.util.TypedValue#changingConfigurations}. 382 * 383 * @return Return true if the resource needs to be loaded, else false. 384 */ 385 public static boolean needNewResources(int configChanges, int interestingChanges) { 386 return (configChanges & (interestingChanges|ActivityInfo.CONFIG_FONT_SCALE)) != 0; 387 } 388 389 /** 390 * Parcelable methods 391 */ 392 public int describeContents() { 393 return 0; 394 } 395 396 public void writeToParcel(Parcel dest, int flags) { 397 dest.writeFloat(fontScale); 398 dest.writeInt(mcc); 399 dest.writeInt(mnc); 400 if (locale == null) { 401 dest.writeInt(0); 402 } else { 403 dest.writeInt(1); 404 dest.writeString(locale.getLanguage()); 405 dest.writeString(locale.getCountry()); 406 dest.writeString(locale.getVariant()); 407 } 408 if(userSetLocale) { 409 dest.writeInt(1); 410 } else { 411 dest.writeInt(0); 412 } 413 dest.writeInt(touchscreen); 414 dest.writeInt(keyboard); 415 dest.writeInt(keyboardHidden); 416 dest.writeInt(hardKeyboardHidden); 417 dest.writeInt(navigation); 418 dest.writeInt(orientation); 419 dest.writeInt(screenLayout); 420 } 421 422 public static final Parcelable.Creator<Configuration> CREATOR 423 = new Parcelable.Creator<Configuration>() { 424 public Configuration createFromParcel(Parcel source) { 425 return new Configuration(source); 426 } 427 428 public Configuration[] newArray(int size) { 429 return new Configuration[size]; 430 } 431 }; 432 433 /** 434 * Construct this Configuration object, reading from the Parcel. 435 */ 436 private Configuration(Parcel source) { 437 fontScale = source.readFloat(); 438 mcc = source.readInt(); 439 mnc = source.readInt(); 440 if (source.readInt() != 0) { 441 locale = new Locale(source.readString(), source.readString(), 442 source.readString()); 443 } 444 userSetLocale = (source.readInt()==1); 445 touchscreen = source.readInt(); 446 keyboard = source.readInt(); 447 keyboardHidden = source.readInt(); 448 hardKeyboardHidden = source.readInt(); 449 navigation = source.readInt(); 450 orientation = source.readInt(); 451 screenLayout = source.readInt(); 452 } 453 454 public int compareTo(Configuration that) { 455 int n; 456 float a = this.fontScale; 457 float b = that.fontScale; 458 if (a < b) return -1; 459 if (a > b) return 1; 460 n = this.mcc - that.mcc; 461 if (n != 0) return n; 462 n = this.mnc - that.mnc; 463 if (n != 0) return n; 464 n = this.locale.getLanguage().compareTo(that.locale.getLanguage()); 465 if (n != 0) return n; 466 n = this.locale.getCountry().compareTo(that.locale.getCountry()); 467 if (n != 0) return n; 468 n = this.locale.getVariant().compareTo(that.locale.getVariant()); 469 if (n != 0) return n; 470 n = this.touchscreen - that.touchscreen; 471 if (n != 0) return n; 472 n = this.keyboard - that.keyboard; 473 if (n != 0) return n; 474 n = this.keyboardHidden - that.keyboardHidden; 475 if (n != 0) return n; 476 n = this.hardKeyboardHidden - that.hardKeyboardHidden; 477 if (n != 0) return n; 478 n = this.navigation - that.navigation; 479 if (n != 0) return n; 480 n = this.orientation - that.orientation; 481 if (n != 0) return n; 482 n = this.screenLayout - that.screenLayout; 483 //if (n != 0) return n; 484 return n; 485 } 486 487 public boolean equals(Configuration that) { 488 if (that == null) return false; 489 if (that == this) return true; 490 return this.compareTo(that) == 0; 491 } 492 493 public boolean equals(Object that) { 494 try { 495 return equals((Configuration)that); 496 } catch (ClassCastException e) { 497 } 498 return false; 499 } 500 501 public int hashCode() { 502 return ((int)this.fontScale) + this.mcc + this.mnc 503 + this.locale.hashCode() + this.touchscreen 504 + this.keyboard + this.keyboardHidden + this.hardKeyboardHidden 505 + this.navigation + this.orientation + this.screenLayout; 506 } 507} 508