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