Configuration.java revision b1a4bf2c4be73c72d2628b6087cf7b256376122a
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 com.android.internal.util.XmlUtils; 20 21import org.xmlpull.v1.XmlPullParser; 22import org.xmlpull.v1.XmlPullParserException; 23import org.xmlpull.v1.XmlSerializer; 24 25import android.annotation.Nullable; 26import android.content.pm.ActivityInfo; 27import android.os.Build; 28import android.os.Parcel; 29import android.os.Parcelable; 30import android.text.TextUtils; 31import android.util.LocaleList; 32import android.view.View; 33 34import java.io.IOException; 35import java.util.ArrayList; 36import java.util.Locale; 37 38/** 39 * This class describes all device configuration information that can 40 * impact the resources the application retrieves. This includes both 41 * user-specified configuration options (locale list and scaling) as well 42 * as device configurations (such as input modes, screen size and screen orientation). 43 * <p>You can acquire this object from {@link Resources}, using {@link 44 * Resources#getConfiguration}. Thus, from an activity, you can get it by chaining the request 45 * with {@link android.app.Activity#getResources}:</p> 46 * <pre>Configuration config = getResources().getConfiguration();</pre> 47 */ 48public final class Configuration implements Parcelable, Comparable<Configuration> { 49 /** @hide */ 50 public static final Configuration EMPTY = new Configuration(); 51 52 /** 53 * Current user preference for the scaling factor for fonts, relative 54 * to the base density scaling. 55 */ 56 public float fontScale; 57 58 /** 59 * IMSI MCC (Mobile Country Code), corresponding to 60 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mcc</a> 61 * resource qualifier. 0 if undefined. 62 */ 63 public int mcc; 64 65 /** 66 * IMSI MNC (Mobile Network Code), corresponding to 67 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mnc</a> 68 * resource qualifier. 0 if undefined. Note that the actual MNC may be 0; in order to check 69 * for this use the {@link #MNC_ZERO} symbol. 70 */ 71 public int mnc; 72 73 /** 74 * Constant used to to represent MNC (Mobile Network Code) zero. 75 * 0 cannot be used, since it is used to represent an undefined MNC. 76 */ 77 public static final int MNC_ZERO = 0xffff; 78 79 /** 80 * Current user preference for the locale, corresponding to 81 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a> 82 * resource qualifier. 83 * 84 * @deprecated Do not set or read this directly. Use {@link #getLocales()} and 85 * {@link #setLocales(LocaleList)}. 86 */ 87 @Deprecated public Locale locale; 88 89 private LocaleList mLocaleList; 90 91 /** 92 * Locale should persist on setting. This is hidden because it is really 93 * questionable whether this is the right way to expose the functionality. 94 * @hide 95 */ 96 public boolean userSetLocale; 97 98 /** Constant for {@link #screenLayout}: bits that encode the size. */ 99 public static final int SCREENLAYOUT_SIZE_MASK = 0x0f; 100 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK} 101 * value indicating that no size has been set. */ 102 public static final int SCREENLAYOUT_SIZE_UNDEFINED = 0x00; 103 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK} 104 * value indicating the screen is at least approximately 320x426 dp units, 105 * corresponds to the 106 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">small</a> 107 * resource qualifier. 108 * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting 109 * Multiple Screens</a> for more information. */ 110 public static final int SCREENLAYOUT_SIZE_SMALL = 0x01; 111 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK} 112 * value indicating the screen is at least approximately 320x470 dp units, 113 * corresponds to the 114 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">normal</a> 115 * resource qualifier. 116 * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting 117 * Multiple Screens</a> for more information. */ 118 public static final int SCREENLAYOUT_SIZE_NORMAL = 0x02; 119 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK} 120 * value indicating the screen is at least approximately 480x640 dp units, 121 * corresponds to the 122 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">large</a> 123 * resource qualifier. 124 * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting 125 * Multiple Screens</a> for more information. */ 126 public static final int SCREENLAYOUT_SIZE_LARGE = 0x03; 127 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK} 128 * value indicating the screen is at least approximately 720x960 dp units, 129 * corresponds to the 130 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">xlarge</a> 131 * resource qualifier. 132 * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting 133 * Multiple Screens</a> for more information.*/ 134 public static final int SCREENLAYOUT_SIZE_XLARGE = 0x04; 135 136 /** Constant for {@link #screenLayout}: bits that encode the aspect ratio. */ 137 public static final int SCREENLAYOUT_LONG_MASK = 0x30; 138 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK} 139 * value indicating that no size has been set. */ 140 public static final int SCREENLAYOUT_LONG_UNDEFINED = 0x00; 141 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK} 142 * value that corresponds to the 143 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenAspectQualifier">notlong</a> 144 * resource qualifier. */ 145 public static final int SCREENLAYOUT_LONG_NO = 0x10; 146 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK} 147 * value that corresponds to the 148 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenAspectQualifier">long</a> 149 * resource qualifier. */ 150 public static final int SCREENLAYOUT_LONG_YES = 0x20; 151 152 /** Constant for {@link #screenLayout}: bits that encode the layout direction. */ 153 public static final int SCREENLAYOUT_LAYOUTDIR_MASK = 0xC0; 154 /** Constant for {@link #screenLayout}: bits shift to get the layout direction. */ 155 public static final int SCREENLAYOUT_LAYOUTDIR_SHIFT = 6; 156 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK} 157 * value indicating that no layout dir has been set. */ 158 public static final int SCREENLAYOUT_LAYOUTDIR_UNDEFINED = 0x00; 159 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK} 160 * value indicating that a layout dir has been set to LTR. */ 161 public static final int SCREENLAYOUT_LAYOUTDIR_LTR = 0x01 << SCREENLAYOUT_LAYOUTDIR_SHIFT; 162 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK} 163 * value indicating that a layout dir has been set to RTL. */ 164 public static final int SCREENLAYOUT_LAYOUTDIR_RTL = 0x02 << SCREENLAYOUT_LAYOUTDIR_SHIFT; 165 166 /** Constant for {@link #screenLayout}: bits that encode roundness of the screen. */ 167 public static final int SCREENLAYOUT_ROUND_MASK = 0x300; 168 /** @hide Constant for {@link #screenLayout}: bit shift to get to screen roundness bits */ 169 public static final int SCREENLAYOUT_ROUND_SHIFT = 8; 170 /** 171 * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating 172 * that it is unknown whether or not the screen has a round shape. 173 */ 174 public static final int SCREENLAYOUT_ROUND_UNDEFINED = 0x00; 175 /** 176 * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating 177 * that the screen does not have a rounded shape. 178 */ 179 public static final int SCREENLAYOUT_ROUND_NO = 0x1 << SCREENLAYOUT_ROUND_SHIFT; 180 /** 181 * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating 182 * that the screen has a rounded shape. Corners may not be visible to the user; 183 * developers should pay special attention to the {@link android.view.WindowInsets} delivered 184 * to views for more information about ensuring content is not obscured. 185 * 186 * <p>Corresponds to the <code>-round</code> resource qualifier.</p> 187 */ 188 public static final int SCREENLAYOUT_ROUND_YES = 0x2 << SCREENLAYOUT_ROUND_SHIFT; 189 190 /** Constant for {@link #screenLayout}: a value indicating that screenLayout is undefined */ 191 public static final int SCREENLAYOUT_UNDEFINED = SCREENLAYOUT_SIZE_UNDEFINED | 192 SCREENLAYOUT_LONG_UNDEFINED | SCREENLAYOUT_LAYOUTDIR_UNDEFINED | 193 SCREENLAYOUT_ROUND_UNDEFINED; 194 195 /** 196 * Special flag we generate to indicate that the screen layout requires 197 * us to use a compatibility mode for apps that are not modern layout 198 * aware. 199 * @hide 200 */ 201 public static final int SCREENLAYOUT_COMPAT_NEEDED = 0x10000000; 202 203 /** 204 * Bit mask of overall layout of the screen. Currently there are two 205 * fields: 206 * <p>The {@link #SCREENLAYOUT_SIZE_MASK} bits define the overall size 207 * of the screen. They may be one of 208 * {@link #SCREENLAYOUT_SIZE_SMALL}, {@link #SCREENLAYOUT_SIZE_NORMAL}, 209 * {@link #SCREENLAYOUT_SIZE_LARGE}, or {@link #SCREENLAYOUT_SIZE_XLARGE}.</p> 210 * 211 * <p>The {@link #SCREENLAYOUT_LONG_MASK} defines whether the screen 212 * is wider/taller than normal. They may be one of 213 * {@link #SCREENLAYOUT_LONG_NO} or {@link #SCREENLAYOUT_LONG_YES}.</p> 214 * 215 * <p>The {@link #SCREENLAYOUT_LAYOUTDIR_MASK} defines whether the screen layout 216 * is either LTR or RTL. They may be one of 217 * {@link #SCREENLAYOUT_LAYOUTDIR_LTR} or {@link #SCREENLAYOUT_LAYOUTDIR_RTL}.</p> 218 * 219 * <p>The {@link #SCREENLAYOUT_ROUND_MASK} defines whether the screen has a rounded 220 * shape. They may be one of {@link #SCREENLAYOUT_ROUND_NO} or {@link #SCREENLAYOUT_ROUND_YES}. 221 * </p> 222 * 223 * <p>See <a href="{@docRoot}guide/practices/screens_support.html">Supporting 224 * Multiple Screens</a> for more information.</p> 225 */ 226 public int screenLayout; 227 228 /** @hide */ 229 static public int resetScreenLayout(int curLayout) { 230 return (curLayout&~(SCREENLAYOUT_LONG_MASK | SCREENLAYOUT_SIZE_MASK 231 | SCREENLAYOUT_COMPAT_NEEDED)) 232 | (SCREENLAYOUT_LONG_YES | SCREENLAYOUT_SIZE_XLARGE); 233 } 234 235 /** @hide */ 236 static public int reduceScreenLayout(int curLayout, int longSizeDp, int shortSizeDp) { 237 int screenLayoutSize; 238 boolean screenLayoutLong; 239 boolean screenLayoutCompatNeeded; 240 241 // These semi-magic numbers define our compatibility modes for 242 // applications with different screens. These are guarantees to 243 // app developers about the space they can expect for a particular 244 // configuration. DO NOT CHANGE! 245 if (longSizeDp < 470) { 246 // This is shorter than an HVGA normal density screen (which 247 // is 480 pixels on its long side). 248 screenLayoutSize = SCREENLAYOUT_SIZE_SMALL; 249 screenLayoutLong = false; 250 screenLayoutCompatNeeded = false; 251 } else { 252 // What size is this screen screen? 253 if (longSizeDp >= 960 && shortSizeDp >= 720) { 254 // 1.5xVGA or larger screens at medium density are the point 255 // at which we consider it to be an extra large screen. 256 screenLayoutSize = SCREENLAYOUT_SIZE_XLARGE; 257 } else if (longSizeDp >= 640 && shortSizeDp >= 480) { 258 // VGA or larger screens at medium density are the point 259 // at which we consider it to be a large screen. 260 screenLayoutSize = SCREENLAYOUT_SIZE_LARGE; 261 } else { 262 screenLayoutSize = SCREENLAYOUT_SIZE_NORMAL; 263 } 264 265 // If this screen is wider than normal HVGA, or taller 266 // than FWVGA, then for old apps we want to run in size 267 // compatibility mode. 268 if (shortSizeDp > 321 || longSizeDp > 570) { 269 screenLayoutCompatNeeded = true; 270 } else { 271 screenLayoutCompatNeeded = false; 272 } 273 274 // Is this a long screen? 275 if (((longSizeDp*3)/5) >= (shortSizeDp-1)) { 276 // Anything wider than WVGA (5:3) is considering to be long. 277 screenLayoutLong = true; 278 } else { 279 screenLayoutLong = false; 280 } 281 } 282 283 // Now reduce the last screenLayout to not be better than what we 284 // have found. 285 if (!screenLayoutLong) { 286 curLayout = (curLayout&~SCREENLAYOUT_LONG_MASK) | SCREENLAYOUT_LONG_NO; 287 } 288 if (screenLayoutCompatNeeded) { 289 curLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED; 290 } 291 int curSize = curLayout&SCREENLAYOUT_SIZE_MASK; 292 if (screenLayoutSize < curSize) { 293 curLayout = (curLayout&~SCREENLAYOUT_SIZE_MASK) | screenLayoutSize; 294 } 295 return curLayout; 296 } 297 298 /** 299 * Check if the Configuration's current {@link #screenLayout} is at 300 * least the given size. 301 * 302 * @param size The desired size, either {@link #SCREENLAYOUT_SIZE_SMALL}, 303 * {@link #SCREENLAYOUT_SIZE_NORMAL}, {@link #SCREENLAYOUT_SIZE_LARGE}, or 304 * {@link #SCREENLAYOUT_SIZE_XLARGE}. 305 * @return Returns true if the current screen layout size is at least 306 * the given size. 307 */ 308 public boolean isLayoutSizeAtLeast(int size) { 309 int cur = screenLayout&SCREENLAYOUT_SIZE_MASK; 310 if (cur == SCREENLAYOUT_SIZE_UNDEFINED) return false; 311 return cur >= size; 312 } 313 314 /** Constant for {@link #touchscreen}: a value indicating that no value has been set. */ 315 public static final int TOUCHSCREEN_UNDEFINED = 0; 316 /** Constant for {@link #touchscreen}, value corresponding to the 317 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#TouchscreenQualifier">notouch</a> 318 * resource qualifier. */ 319 public static final int TOUCHSCREEN_NOTOUCH = 1; 320 /** @deprecated Not currently supported or used. */ 321 @Deprecated public static final int TOUCHSCREEN_STYLUS = 2; 322 /** Constant for {@link #touchscreen}, value corresponding to the 323 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#TouchscreenQualifier">finger</a> 324 * resource qualifier. */ 325 public static final int TOUCHSCREEN_FINGER = 3; 326 327 /** 328 * The kind of touch screen attached to the device. 329 * One of: {@link #TOUCHSCREEN_NOTOUCH}, {@link #TOUCHSCREEN_FINGER}. 330 */ 331 public int touchscreen; 332 333 /** Constant for {@link #keyboard}: a value indicating that no value has been set. */ 334 public static final int KEYBOARD_UNDEFINED = 0; 335 /** Constant for {@link #keyboard}, value corresponding to the 336 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">nokeys</a> 337 * resource qualifier. */ 338 public static final int KEYBOARD_NOKEYS = 1; 339 /** Constant for {@link #keyboard}, value corresponding to the 340 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">qwerty</a> 341 * resource qualifier. */ 342 public static final int KEYBOARD_QWERTY = 2; 343 /** Constant for {@link #keyboard}, value corresponding to the 344 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">12key</a> 345 * resource qualifier. */ 346 public static final int KEYBOARD_12KEY = 3; 347 348 /** 349 * The kind of keyboard attached to the device. 350 * One of: {@link #KEYBOARD_NOKEYS}, {@link #KEYBOARD_QWERTY}, 351 * {@link #KEYBOARD_12KEY}. 352 */ 353 public int keyboard; 354 355 /** Constant for {@link #keyboardHidden}: a value indicating that no value has been set. */ 356 public static final int KEYBOARDHIDDEN_UNDEFINED = 0; 357 /** Constant for {@link #keyboardHidden}, value corresponding to the 358 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keysexposed</a> 359 * resource qualifier. */ 360 public static final int KEYBOARDHIDDEN_NO = 1; 361 /** Constant for {@link #keyboardHidden}, value corresponding to the 362 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keyshidden</a> 363 * resource qualifier. */ 364 public static final int KEYBOARDHIDDEN_YES = 2; 365 /** Constant matching actual resource implementation. {@hide} */ 366 public static final int KEYBOARDHIDDEN_SOFT = 3; 367 368 /** 369 * A flag indicating whether any keyboard is available. Unlike 370 * {@link #hardKeyboardHidden}, this also takes into account a soft 371 * keyboard, so if the hard keyboard is hidden but there is soft 372 * keyboard available, it will be set to NO. Value is one of: 373 * {@link #KEYBOARDHIDDEN_NO}, {@link #KEYBOARDHIDDEN_YES}. 374 */ 375 public int keyboardHidden; 376 377 /** Constant for {@link #hardKeyboardHidden}: a value indicating that no value has been set. */ 378 public static final int HARDKEYBOARDHIDDEN_UNDEFINED = 0; 379 /** Constant for {@link #hardKeyboardHidden}, value corresponding to the 380 * physical keyboard being exposed. */ 381 public static final int HARDKEYBOARDHIDDEN_NO = 1; 382 /** Constant for {@link #hardKeyboardHidden}, value corresponding to the 383 * physical keyboard being hidden. */ 384 public static final int HARDKEYBOARDHIDDEN_YES = 2; 385 386 /** 387 * A flag indicating whether the hard keyboard has been hidden. This will 388 * be set on a device with a mechanism to hide the keyboard from the 389 * user, when that mechanism is closed. One of: 390 * {@link #HARDKEYBOARDHIDDEN_NO}, {@link #HARDKEYBOARDHIDDEN_YES}. 391 */ 392 public int hardKeyboardHidden; 393 394 /** Constant for {@link #navigation}: a value indicating that no value has been set. */ 395 public static final int NAVIGATION_UNDEFINED = 0; 396 /** Constant for {@link #navigation}, value corresponding to the 397 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">nonav</a> 398 * resource qualifier. */ 399 public static final int NAVIGATION_NONAV = 1; 400 /** Constant for {@link #navigation}, value corresponding to the 401 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">dpad</a> 402 * resource qualifier. */ 403 public static final int NAVIGATION_DPAD = 2; 404 /** Constant for {@link #navigation}, value corresponding to the 405 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">trackball</a> 406 * resource qualifier. */ 407 public static final int NAVIGATION_TRACKBALL = 3; 408 /** Constant for {@link #navigation}, value corresponding to the 409 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">wheel</a> 410 * resource qualifier. */ 411 public static final int NAVIGATION_WHEEL = 4; 412 413 /** 414 * The kind of navigation method available on the device. 415 * One of: {@link #NAVIGATION_NONAV}, {@link #NAVIGATION_DPAD}, 416 * {@link #NAVIGATION_TRACKBALL}, {@link #NAVIGATION_WHEEL}. 417 */ 418 public int navigation; 419 420 /** Constant for {@link #navigationHidden}: a value indicating that no value has been set. */ 421 public static final int NAVIGATIONHIDDEN_UNDEFINED = 0; 422 /** Constant for {@link #navigationHidden}, value corresponding to the 423 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavAvailQualifier">navexposed</a> 424 * resource qualifier. */ 425 public static final int NAVIGATIONHIDDEN_NO = 1; 426 /** Constant for {@link #navigationHidden}, value corresponding to the 427 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavAvailQualifier">navhidden</a> 428 * resource qualifier. */ 429 public static final int NAVIGATIONHIDDEN_YES = 2; 430 431 /** 432 * A flag indicating whether any 5-way or DPAD navigation available. 433 * This will be set on a device with a mechanism to hide the navigation 434 * controls from the user, when that mechanism is closed. One of: 435 * {@link #NAVIGATIONHIDDEN_NO}, {@link #NAVIGATIONHIDDEN_YES}. 436 */ 437 public int navigationHidden; 438 439 /** Constant for {@link #orientation}: a value indicating that no value has been set. */ 440 public static final int ORIENTATION_UNDEFINED = 0; 441 /** Constant for {@link #orientation}, value corresponding to the 442 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#OrientationQualifier">port</a> 443 * resource qualifier. */ 444 public static final int ORIENTATION_PORTRAIT = 1; 445 /** Constant for {@link #orientation}, value corresponding to the 446 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#OrientationQualifier">land</a> 447 * resource qualifier. */ 448 public static final int ORIENTATION_LANDSCAPE = 2; 449 /** @deprecated Not currently supported or used. */ 450 @Deprecated public static final int ORIENTATION_SQUARE = 3; 451 452 /** 453 * Overall orientation of the screen. May be one of 454 * {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}. 455 */ 456 public int orientation; 457 458 /** Constant for {@link #uiMode}: bits that encode the mode type. */ 459 public static final int UI_MODE_TYPE_MASK = 0x0f; 460 /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK} 461 * value indicating that no mode type has been set. */ 462 public static final int UI_MODE_TYPE_UNDEFINED = 0x00; 463 /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK} 464 * value that corresponds to 465 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">no 466 * UI mode</a> resource qualifier specified. */ 467 public static final int UI_MODE_TYPE_NORMAL = 0x01; 468 /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK} 469 * value that corresponds to the 470 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">desk</a> 471 * resource qualifier. */ 472 public static final int UI_MODE_TYPE_DESK = 0x02; 473 /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK} 474 * value that corresponds to the 475 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">car</a> 476 * resource qualifier. */ 477 public static final int UI_MODE_TYPE_CAR = 0x03; 478 /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK} 479 * value that corresponds to the 480 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">television</a> 481 * resource qualifier. */ 482 public static final int UI_MODE_TYPE_TELEVISION = 0x04; 483 /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK} 484 * value that corresponds to the 485 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">appliance</a> 486 * resource qualifier. */ 487 public static final int UI_MODE_TYPE_APPLIANCE = 0x05; 488 /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK} 489 * value that corresponds to the 490 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">watch</a> 491 * resource qualifier. */ 492 public static final int UI_MODE_TYPE_WATCH = 0x06; 493 494 /** Constant for {@link #uiMode}: bits that encode the night mode. */ 495 public static final int UI_MODE_NIGHT_MASK = 0x30; 496 /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK} 497 * value indicating that no mode type has been set. */ 498 public static final int UI_MODE_NIGHT_UNDEFINED = 0x00; 499 /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK} 500 * value that corresponds to the 501 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NightQualifier">notnight</a> 502 * resource qualifier. */ 503 public static final int UI_MODE_NIGHT_NO = 0x10; 504 /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK} 505 * value that corresponds to the 506 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NightQualifier">night</a> 507 * resource qualifier. */ 508 public static final int UI_MODE_NIGHT_YES = 0x20; 509 510 /** 511 * Bit mask of the ui mode. Currently there are two fields: 512 * <p>The {@link #UI_MODE_TYPE_MASK} bits define the overall ui mode of the 513 * device. They may be one of {@link #UI_MODE_TYPE_UNDEFINED}, 514 * {@link #UI_MODE_TYPE_NORMAL}, {@link #UI_MODE_TYPE_DESK}, 515 * {@link #UI_MODE_TYPE_CAR}, {@link #UI_MODE_TYPE_TELEVISION}, 516 * {@link #UI_MODE_TYPE_APPLIANCE}, or {@link #UI_MODE_TYPE_WATCH}. 517 * 518 * <p>The {@link #UI_MODE_NIGHT_MASK} defines whether the screen 519 * is in a special mode. They may be one of {@link #UI_MODE_NIGHT_UNDEFINED}, 520 * {@link #UI_MODE_NIGHT_NO} or {@link #UI_MODE_NIGHT_YES}. 521 */ 522 public int uiMode; 523 524 /** 525 * Default value for {@link #screenWidthDp} indicating that no width 526 * has been specified. 527 */ 528 public static final int SCREEN_WIDTH_DP_UNDEFINED = 0; 529 530 /** 531 * The current width of the available screen space, in dp units, 532 * corresponding to 533 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenWidthQualifier">screen 534 * width</a> resource qualifier. Set to 535 * {@link #SCREEN_WIDTH_DP_UNDEFINED} if no width is specified. 536 */ 537 public int screenWidthDp; 538 539 /** 540 * Default value for {@link #screenHeightDp} indicating that no width 541 * has been specified. 542 */ 543 public static final int SCREEN_HEIGHT_DP_UNDEFINED = 0; 544 545 /** 546 * The current height of the available screen space, in dp units, 547 * corresponding to 548 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenHeightQualifier">screen 549 * height</a> resource qualifier. Set to 550 * {@link #SCREEN_HEIGHT_DP_UNDEFINED} if no height is specified. 551 */ 552 public int screenHeightDp; 553 554 /** 555 * Default value for {@link #smallestScreenWidthDp} indicating that no width 556 * has been specified. 557 */ 558 public static final int SMALLEST_SCREEN_WIDTH_DP_UNDEFINED = 0; 559 560 /** 561 * The smallest screen size an application will see in normal operation, 562 * corresponding to 563 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#SmallestScreenWidthQualifier">smallest 564 * screen width</a> resource qualifier. 565 * This is the smallest value of both screenWidthDp and screenHeightDp 566 * in both portrait and landscape. Set to 567 * {@link #SMALLEST_SCREEN_WIDTH_DP_UNDEFINED} if no width is specified. 568 */ 569 public int smallestScreenWidthDp; 570 571 /** 572 * Default value for {@link #densityDpi} indicating that no width 573 * has been specified. 574 */ 575 public static final int DENSITY_DPI_UNDEFINED = 0; 576 577 /** 578 * Value for {@link #densityDpi} for resources that scale to any density (vector drawables). 579 * {@hide} 580 */ 581 public static final int DENSITY_DPI_ANY = 0xfffe; 582 583 /** 584 * Value for {@link #densityDpi} for resources that are not meant to be scaled. 585 * {@hide} 586 */ 587 public static final int DENSITY_DPI_NONE = 0xffff; 588 589 /** 590 * The target screen density being rendered to, 591 * corresponding to 592 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#DensityQualifier">density</a> 593 * resource qualifier. Set to 594 * {@link #DENSITY_DPI_UNDEFINED} if no density is specified. 595 */ 596 public int densityDpi; 597 598 /** @hide Hack to get this information from WM to app running in compat mode. */ 599 public int compatScreenWidthDp; 600 /** @hide Hack to get this information from WM to app running in compat mode. */ 601 public int compatScreenHeightDp; 602 /** @hide Hack to get this information from WM to app running in compat mode. */ 603 public int compatSmallestScreenWidthDp; 604 605 /** 606 * @hide Internal book-keeping. 607 */ 608 public int seq; 609 610 /** @hide Native-specific bit mask for MCC config; DO NOT USE UNLESS YOU ARE SURE. */ 611 public static final int NATIVE_CONFIG_MCC = 0x0001; 612 /** @hide Native-specific bit mask for MNC config; DO NOT USE UNLESS YOU ARE SURE. */ 613 public static final int NATIVE_CONFIG_MNC = 0x0002; 614 /** @hide Native-specific bit mask for LOCALE config; DO NOT USE UNLESS YOU ARE SURE. */ 615 public static final int NATIVE_CONFIG_LOCALE = 0x0004; 616 /** @hide Native-specific bit mask for TOUCHSCREEN config; DO NOT USE UNLESS YOU ARE SURE. */ 617 public static final int NATIVE_CONFIG_TOUCHSCREEN = 0x0008; 618 /** @hide Native-specific bit mask for KEYBOARD config; DO NOT USE UNLESS YOU ARE SURE. */ 619 public static final int NATIVE_CONFIG_KEYBOARD = 0x0010; 620 /** @hide Native-specific bit mask for KEYBOARD_HIDDEN config; DO NOT USE UNLESS YOU 621 * ARE SURE. */ 622 public static final int NATIVE_CONFIG_KEYBOARD_HIDDEN = 0x0020; 623 /** @hide Native-specific bit mask for NAVIGATION config; DO NOT USE UNLESS YOU ARE SURE. */ 624 public static final int NATIVE_CONFIG_NAVIGATION = 0x0040; 625 /** @hide Native-specific bit mask for ORIENTATION config; DO NOT USE UNLESS YOU ARE SURE. */ 626 public static final int NATIVE_CONFIG_ORIENTATION = 0x0080; 627 /** @hide Native-specific bit mask for DENSITY config; DO NOT USE UNLESS YOU ARE SURE. */ 628 public static final int NATIVE_CONFIG_DENSITY = 0x0100; 629 /** @hide Native-specific bit mask for SCREEN_SIZE config; DO NOT USE UNLESS YOU ARE SURE. */ 630 public static final int NATIVE_CONFIG_SCREEN_SIZE = 0x0200; 631 /** @hide Native-specific bit mask for VERSION config; DO NOT USE UNLESS YOU ARE SURE. */ 632 public static final int NATIVE_CONFIG_VERSION = 0x0400; 633 /** @hide Native-specific bit mask for SCREEN_LAYOUT config; DO NOT USE UNLESS YOU ARE SURE. */ 634 public static final int NATIVE_CONFIG_SCREEN_LAYOUT = 0x0800; 635 /** @hide Native-specific bit mask for UI_MODE config; DO NOT USE UNLESS YOU ARE SURE. */ 636 public static final int NATIVE_CONFIG_UI_MODE = 0x1000; 637 /** @hide Native-specific bit mask for SMALLEST_SCREEN_SIZE config; DO NOT USE UNLESS YOU 638 * ARE SURE. */ 639 public static final int NATIVE_CONFIG_SMALLEST_SCREEN_SIZE = 0x2000; 640 /** @hide Native-specific bit mask for LAYOUTDIR config ; DO NOT USE UNLESS YOU ARE SURE.*/ 641 public static final int NATIVE_CONFIG_LAYOUTDIR = 0x4000; 642 643 /** 644 * Construct an invalid Configuration. You must call {@link #setToDefaults} 645 * for this object to be valid. {@more} 646 */ 647 public Configuration() { 648 setToDefaults(); 649 } 650 651 /** 652 * Makes a deep copy suitable for modification. 653 */ 654 public Configuration(Configuration o) { 655 setTo(o); 656 } 657 658 /* This brings mLocaleList in sync with locale in case a user of the older API who doesn't know 659 * about setLocales() has changed locale directly. */ 660 private void fixUpLocaleList() { 661 if ((locale == null && !mLocaleList.isEmpty()) || 662 (locale != null && !locale.equals(mLocaleList.getPrimary()))) { 663 mLocaleList = new LocaleList(locale); 664 } 665 } 666 667 public void setTo(Configuration o) { 668 fontScale = o.fontScale; 669 mcc = o.mcc; 670 mnc = o.mnc; 671 if (o.locale != null) { 672 locale = (Locale) o.locale.clone(); 673 } 674 o.fixUpLocaleList(); 675 mLocaleList = o.mLocaleList; 676 userSetLocale = o.userSetLocale; 677 touchscreen = o.touchscreen; 678 keyboard = o.keyboard; 679 keyboardHidden = o.keyboardHidden; 680 hardKeyboardHidden = o.hardKeyboardHidden; 681 navigation = o.navigation; 682 navigationHidden = o.navigationHidden; 683 orientation = o.orientation; 684 screenLayout = o.screenLayout; 685 uiMode = o.uiMode; 686 screenWidthDp = o.screenWidthDp; 687 screenHeightDp = o.screenHeightDp; 688 smallestScreenWidthDp = o.smallestScreenWidthDp; 689 densityDpi = o.densityDpi; 690 compatScreenWidthDp = o.compatScreenWidthDp; 691 compatScreenHeightDp = o.compatScreenHeightDp; 692 compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp; 693 seq = o.seq; 694 } 695 696 public String toString() { 697 StringBuilder sb = new StringBuilder(128); 698 sb.append("{"); 699 sb.append(fontScale); 700 sb.append(" "); 701 if (mcc != 0) { 702 sb.append(mcc); 703 sb.append("mcc"); 704 } else { 705 sb.append("?mcc"); 706 } 707 if (mnc != 0) { 708 sb.append(mnc); 709 sb.append("mnc"); 710 } else { 711 sb.append("?mnc"); 712 } 713 fixUpLocaleList(); 714 if (!mLocaleList.isEmpty()) { 715 sb.append(" "); 716 sb.append(mLocaleList); 717 } else { 718 sb.append(" ?localeList"); 719 } 720 int layoutDir = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK); 721 switch (layoutDir) { 722 case SCREENLAYOUT_LAYOUTDIR_UNDEFINED: sb.append(" ?layoutDir"); break; 723 case SCREENLAYOUT_LAYOUTDIR_LTR: sb.append(" ldltr"); break; 724 case SCREENLAYOUT_LAYOUTDIR_RTL: sb.append(" ldrtl"); break; 725 default: sb.append(" layoutDir="); 726 sb.append(layoutDir >> SCREENLAYOUT_LAYOUTDIR_SHIFT); break; 727 } 728 if (smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { 729 sb.append(" sw"); sb.append(smallestScreenWidthDp); sb.append("dp"); 730 } else { 731 sb.append(" ?swdp"); 732 } 733 if (screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) { 734 sb.append(" w"); sb.append(screenWidthDp); sb.append("dp"); 735 } else { 736 sb.append(" ?wdp"); 737 } 738 if (screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) { 739 sb.append(" h"); sb.append(screenHeightDp); sb.append("dp"); 740 } else { 741 sb.append(" ?hdp"); 742 } 743 if (densityDpi != DENSITY_DPI_UNDEFINED) { 744 sb.append(" "); sb.append(densityDpi); sb.append("dpi"); 745 } else { 746 sb.append(" ?density"); 747 } 748 switch ((screenLayout&SCREENLAYOUT_SIZE_MASK)) { 749 case SCREENLAYOUT_SIZE_UNDEFINED: sb.append(" ?lsize"); break; 750 case SCREENLAYOUT_SIZE_SMALL: sb.append(" smll"); break; 751 case SCREENLAYOUT_SIZE_NORMAL: sb.append(" nrml"); break; 752 case SCREENLAYOUT_SIZE_LARGE: sb.append(" lrg"); break; 753 case SCREENLAYOUT_SIZE_XLARGE: sb.append(" xlrg"); break; 754 default: sb.append(" layoutSize="); 755 sb.append(screenLayout&SCREENLAYOUT_SIZE_MASK); break; 756 } 757 switch ((screenLayout&SCREENLAYOUT_LONG_MASK)) { 758 case SCREENLAYOUT_LONG_UNDEFINED: sb.append(" ?long"); break; 759 case SCREENLAYOUT_LONG_NO: /* not-long is not interesting to print */ break; 760 case SCREENLAYOUT_LONG_YES: sb.append(" long"); break; 761 default: sb.append(" layoutLong="); 762 sb.append(screenLayout&SCREENLAYOUT_LONG_MASK); break; 763 } 764 switch (orientation) { 765 case ORIENTATION_UNDEFINED: sb.append(" ?orien"); break; 766 case ORIENTATION_LANDSCAPE: sb.append(" land"); break; 767 case ORIENTATION_PORTRAIT: sb.append(" port"); break; 768 default: sb.append(" orien="); sb.append(orientation); break; 769 } 770 switch ((uiMode&UI_MODE_TYPE_MASK)) { 771 case UI_MODE_TYPE_UNDEFINED: sb.append(" ?uimode"); break; 772 case UI_MODE_TYPE_NORMAL: /* normal is not interesting to print */ break; 773 case UI_MODE_TYPE_DESK: sb.append(" desk"); break; 774 case UI_MODE_TYPE_CAR: sb.append(" car"); break; 775 case UI_MODE_TYPE_TELEVISION: sb.append(" television"); break; 776 case UI_MODE_TYPE_APPLIANCE: sb.append(" appliance"); break; 777 case UI_MODE_TYPE_WATCH: sb.append(" watch"); break; 778 default: sb.append(" uimode="); sb.append(uiMode&UI_MODE_TYPE_MASK); break; 779 } 780 switch ((uiMode&UI_MODE_NIGHT_MASK)) { 781 case UI_MODE_NIGHT_UNDEFINED: sb.append(" ?night"); break; 782 case UI_MODE_NIGHT_NO: /* not-night is not interesting to print */ break; 783 case UI_MODE_NIGHT_YES: sb.append(" night"); break; 784 default: sb.append(" night="); sb.append(uiMode&UI_MODE_NIGHT_MASK); break; 785 } 786 switch (touchscreen) { 787 case TOUCHSCREEN_UNDEFINED: sb.append(" ?touch"); break; 788 case TOUCHSCREEN_NOTOUCH: sb.append(" -touch"); break; 789 case TOUCHSCREEN_STYLUS: sb.append(" stylus"); break; 790 case TOUCHSCREEN_FINGER: sb.append(" finger"); break; 791 default: sb.append(" touch="); sb.append(touchscreen); break; 792 } 793 switch (keyboard) { 794 case KEYBOARD_UNDEFINED: sb.append(" ?keyb"); break; 795 case KEYBOARD_NOKEYS: sb.append(" -keyb"); break; 796 case KEYBOARD_QWERTY: sb.append(" qwerty"); break; 797 case KEYBOARD_12KEY: sb.append(" 12key"); break; 798 default: sb.append(" keys="); sb.append(keyboard); break; 799 } 800 switch (keyboardHidden) { 801 case KEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break; 802 case KEYBOARDHIDDEN_NO: sb.append("/v"); break; 803 case KEYBOARDHIDDEN_YES: sb.append("/h"); break; 804 case KEYBOARDHIDDEN_SOFT: sb.append("/s"); break; 805 default: sb.append("/"); sb.append(keyboardHidden); break; 806 } 807 switch (hardKeyboardHidden) { 808 case HARDKEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break; 809 case HARDKEYBOARDHIDDEN_NO: sb.append("/v"); break; 810 case HARDKEYBOARDHIDDEN_YES: sb.append("/h"); break; 811 default: sb.append("/"); sb.append(hardKeyboardHidden); break; 812 } 813 switch (navigation) { 814 case NAVIGATION_UNDEFINED: sb.append(" ?nav"); break; 815 case NAVIGATION_NONAV: sb.append(" -nav"); break; 816 case NAVIGATION_DPAD: sb.append(" dpad"); break; 817 case NAVIGATION_TRACKBALL: sb.append(" tball"); break; 818 case NAVIGATION_WHEEL: sb.append(" wheel"); break; 819 default: sb.append(" nav="); sb.append(navigation); break; 820 } 821 switch (navigationHidden) { 822 case NAVIGATIONHIDDEN_UNDEFINED: sb.append("/?"); break; 823 case NAVIGATIONHIDDEN_NO: sb.append("/v"); break; 824 case NAVIGATIONHIDDEN_YES: sb.append("/h"); break; 825 default: sb.append("/"); sb.append(navigationHidden); break; 826 } 827 if (seq != 0) { 828 sb.append(" s."); 829 sb.append(seq); 830 } 831 sb.append('}'); 832 return sb.toString(); 833 } 834 835 /** 836 * Set this object to the system defaults. 837 */ 838 public void setToDefaults() { 839 fontScale = 1; 840 mcc = mnc = 0; 841 mLocaleList = LocaleList.getEmptyLocaleList(); 842 locale = null; 843 userSetLocale = false; 844 touchscreen = TOUCHSCREEN_UNDEFINED; 845 keyboard = KEYBOARD_UNDEFINED; 846 keyboardHidden = KEYBOARDHIDDEN_UNDEFINED; 847 hardKeyboardHidden = HARDKEYBOARDHIDDEN_UNDEFINED; 848 navigation = NAVIGATION_UNDEFINED; 849 navigationHidden = NAVIGATIONHIDDEN_UNDEFINED; 850 orientation = ORIENTATION_UNDEFINED; 851 screenLayout = SCREENLAYOUT_UNDEFINED; 852 uiMode = UI_MODE_TYPE_UNDEFINED; 853 screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED; 854 screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED; 855 smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; 856 densityDpi = DENSITY_DPI_UNDEFINED; 857 seq = 0; 858 } 859 860 /** {@hide} */ 861 @Deprecated public void makeDefault() { 862 setToDefaults(); 863 } 864 865 /** 866 * Copy the fields from delta into this Configuration object, keeping 867 * track of which ones have changed. Any undefined fields in 868 * <var>delta</var> are ignored and not copied in to the current 869 * Configuration. 870 * @return Returns a bit mask of the changed fields, as per 871 * {@link #diff}. 872 */ 873 public int updateFrom(Configuration delta) { 874 int changed = 0; 875 if (delta.fontScale > 0 && fontScale != delta.fontScale) { 876 changed |= ActivityInfo.CONFIG_FONT_SCALE; 877 fontScale = delta.fontScale; 878 } 879 if (delta.mcc != 0 && mcc != delta.mcc) { 880 changed |= ActivityInfo.CONFIG_MCC; 881 mcc = delta.mcc; 882 } 883 if (delta.mnc != 0 && mnc != delta.mnc) { 884 changed |= ActivityInfo.CONFIG_MNC; 885 mnc = delta.mnc; 886 } 887 fixUpLocaleList(); 888 delta.fixUpLocaleList(); 889 if (!delta.mLocaleList.isEmpty() && !mLocaleList.equals(delta.mLocaleList)) { 890 changed |= ActivityInfo.CONFIG_LOCALE; 891 mLocaleList = delta.mLocaleList; 892 // delta.locale can't be null, since delta.mLocaleList is not empty. 893 if (!delta.locale.equals(locale)) { 894 locale = (Locale) delta.locale.clone(); 895 // If locale has changed, then layout direction is also changed ... 896 changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; 897 // ... and we need to update the layout direction (represented by the first 898 // 2 most significant bits in screenLayout). 899 setLayoutDirection(locale); 900 } 901 } 902 final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK; 903 if (deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED && 904 deltaScreenLayoutDir != (screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) { 905 screenLayout = (screenLayout & ~SCREENLAYOUT_LAYOUTDIR_MASK) | deltaScreenLayoutDir; 906 changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; 907 } 908 if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0))) 909 { 910 changed |= ActivityInfo.CONFIG_LOCALE; 911 userSetLocale = true; 912 } 913 if (delta.touchscreen != TOUCHSCREEN_UNDEFINED 914 && touchscreen != delta.touchscreen) { 915 changed |= ActivityInfo.CONFIG_TOUCHSCREEN; 916 touchscreen = delta.touchscreen; 917 } 918 if (delta.keyboard != KEYBOARD_UNDEFINED 919 && keyboard != delta.keyboard) { 920 changed |= ActivityInfo.CONFIG_KEYBOARD; 921 keyboard = delta.keyboard; 922 } 923 if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED 924 && keyboardHidden != delta.keyboardHidden) { 925 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 926 keyboardHidden = delta.keyboardHidden; 927 } 928 if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED 929 && hardKeyboardHidden != delta.hardKeyboardHidden) { 930 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 931 hardKeyboardHidden = delta.hardKeyboardHidden; 932 } 933 if (delta.navigation != NAVIGATION_UNDEFINED 934 && navigation != delta.navigation) { 935 changed |= ActivityInfo.CONFIG_NAVIGATION; 936 navigation = delta.navigation; 937 } 938 if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED 939 && navigationHidden != delta.navigationHidden) { 940 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 941 navigationHidden = delta.navigationHidden; 942 } 943 if (delta.orientation != ORIENTATION_UNDEFINED 944 && orientation != delta.orientation) { 945 changed |= ActivityInfo.CONFIG_ORIENTATION; 946 orientation = delta.orientation; 947 } 948 if (getScreenLayoutNoDirection(delta.screenLayout) != 949 (SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED) 950 && (getScreenLayoutNoDirection(screenLayout) != 951 getScreenLayoutNoDirection(delta.screenLayout))) { 952 changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; 953 // We need to preserve the previous layout dir bits if they were defined 954 if ((delta.screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK) == 0) { 955 screenLayout = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK)|delta.screenLayout; 956 } else { 957 screenLayout = delta.screenLayout; 958 } 959 } 960 if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED) 961 && uiMode != delta.uiMode) { 962 changed |= ActivityInfo.CONFIG_UI_MODE; 963 if ((delta.uiMode&UI_MODE_TYPE_MASK) != UI_MODE_TYPE_UNDEFINED) { 964 uiMode = (uiMode&~UI_MODE_TYPE_MASK) 965 | (delta.uiMode&UI_MODE_TYPE_MASK); 966 } 967 if ((delta.uiMode&UI_MODE_NIGHT_MASK) != UI_MODE_NIGHT_UNDEFINED) { 968 uiMode = (uiMode&~UI_MODE_NIGHT_MASK) 969 | (delta.uiMode&UI_MODE_NIGHT_MASK); 970 } 971 } 972 if (delta.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED 973 && screenWidthDp != delta.screenWidthDp) { 974 changed |= ActivityInfo.CONFIG_SCREEN_SIZE; 975 screenWidthDp = delta.screenWidthDp; 976 } 977 if (delta.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED 978 && screenHeightDp != delta.screenHeightDp) { 979 changed |= ActivityInfo.CONFIG_SCREEN_SIZE; 980 screenHeightDp = delta.screenHeightDp; 981 } 982 if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED 983 && smallestScreenWidthDp != delta.smallestScreenWidthDp) { 984 changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; 985 smallestScreenWidthDp = delta.smallestScreenWidthDp; 986 } 987 if (delta.densityDpi != DENSITY_DPI_UNDEFINED && 988 densityDpi != delta.densityDpi) { 989 changed |= ActivityInfo.CONFIG_DENSITY; 990 densityDpi = delta.densityDpi; 991 } 992 if (delta.compatScreenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) { 993 compatScreenWidthDp = delta.compatScreenWidthDp; 994 } 995 if (delta.compatScreenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) { 996 compatScreenHeightDp = delta.compatScreenHeightDp; 997 } 998 if (delta.compatSmallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { 999 compatSmallestScreenWidthDp = delta.compatSmallestScreenWidthDp; 1000 } 1001 if (delta.seq != 0) { 1002 seq = delta.seq; 1003 } 1004 1005 return changed; 1006 } 1007 1008 /** 1009 * Return a bit mask of the differences between this Configuration 1010 * object and the given one. Does not change the values of either. Any 1011 * undefined fields in <var>delta</var> are ignored. 1012 * @return Returns a bit mask indicating which configuration 1013 * values has changed, containing any combination of 1014 * {@link android.content.pm.ActivityInfo#CONFIG_FONT_SCALE 1015 * PackageManager.ActivityInfo.CONFIG_FONT_SCALE}, 1016 * {@link android.content.pm.ActivityInfo#CONFIG_MCC 1017 * PackageManager.ActivityInfo.CONFIG_MCC}, 1018 * {@link android.content.pm.ActivityInfo#CONFIG_MNC 1019 * PackageManager.ActivityInfo.CONFIG_MNC}, 1020 * {@link android.content.pm.ActivityInfo#CONFIG_LOCALE 1021 * PackageManager.ActivityInfo.CONFIG_LOCALE}, 1022 * {@link android.content.pm.ActivityInfo#CONFIG_TOUCHSCREEN 1023 * PackageManager.ActivityInfo.CONFIG_TOUCHSCREEN}, 1024 * {@link android.content.pm.ActivityInfo#CONFIG_KEYBOARD 1025 * PackageManager.ActivityInfo.CONFIG_KEYBOARD}, 1026 * {@link android.content.pm.ActivityInfo#CONFIG_NAVIGATION 1027 * PackageManager.ActivityInfo.CONFIG_NAVIGATION}, 1028 * {@link android.content.pm.ActivityInfo#CONFIG_ORIENTATION 1029 * PackageManager.ActivityInfo.CONFIG_ORIENTATION}, 1030 * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_LAYOUT 1031 * PackageManager.ActivityInfo.CONFIG_SCREEN_LAYOUT}, or 1032 * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_SIZE 1033 * PackageManager.ActivityInfo.CONFIG_SCREEN_SIZE}, or 1034 * {@link android.content.pm.ActivityInfo#CONFIG_SMALLEST_SCREEN_SIZE 1035 * PackageManager.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE}. 1036 * {@link android.content.pm.ActivityInfo#CONFIG_LAYOUT_DIRECTION 1037 * PackageManager.ActivityInfo.CONFIG_LAYOUT_DIRECTION}. 1038 */ 1039 public int diff(Configuration delta) { 1040 int changed = 0; 1041 if (delta.fontScale > 0 && fontScale != delta.fontScale) { 1042 changed |= ActivityInfo.CONFIG_FONT_SCALE; 1043 } 1044 if (delta.mcc != 0 && mcc != delta.mcc) { 1045 changed |= ActivityInfo.CONFIG_MCC; 1046 } 1047 if (delta.mnc != 0 && mnc != delta.mnc) { 1048 changed |= ActivityInfo.CONFIG_MNC; 1049 } 1050 fixUpLocaleList(); 1051 delta.fixUpLocaleList(); 1052 if (!delta.mLocaleList.isEmpty() && !mLocaleList.equals(delta.mLocaleList)) { 1053 changed |= ActivityInfo.CONFIG_LOCALE; 1054 changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; 1055 } 1056 final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK; 1057 if (deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED && 1058 deltaScreenLayoutDir != (screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) { 1059 changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; 1060 } 1061 if (delta.touchscreen != TOUCHSCREEN_UNDEFINED 1062 && touchscreen != delta.touchscreen) { 1063 changed |= ActivityInfo.CONFIG_TOUCHSCREEN; 1064 } 1065 if (delta.keyboard != KEYBOARD_UNDEFINED 1066 && keyboard != delta.keyboard) { 1067 changed |= ActivityInfo.CONFIG_KEYBOARD; 1068 } 1069 if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED 1070 && keyboardHidden != delta.keyboardHidden) { 1071 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 1072 } 1073 if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED 1074 && hardKeyboardHidden != delta.hardKeyboardHidden) { 1075 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 1076 } 1077 if (delta.navigation != NAVIGATION_UNDEFINED 1078 && navigation != delta.navigation) { 1079 changed |= ActivityInfo.CONFIG_NAVIGATION; 1080 } 1081 if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED 1082 && navigationHidden != delta.navigationHidden) { 1083 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 1084 } 1085 if (delta.orientation != ORIENTATION_UNDEFINED 1086 && orientation != delta.orientation) { 1087 changed |= ActivityInfo.CONFIG_ORIENTATION; 1088 } 1089 if (getScreenLayoutNoDirection(delta.screenLayout) != 1090 (SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED) 1091 && getScreenLayoutNoDirection(screenLayout) != 1092 getScreenLayoutNoDirection(delta.screenLayout)) { 1093 changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; 1094 } 1095 if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED) 1096 && uiMode != delta.uiMode) { 1097 changed |= ActivityInfo.CONFIG_UI_MODE; 1098 } 1099 if (delta.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED 1100 && screenWidthDp != delta.screenWidthDp) { 1101 changed |= ActivityInfo.CONFIG_SCREEN_SIZE; 1102 } 1103 if (delta.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED 1104 && screenHeightDp != delta.screenHeightDp) { 1105 changed |= ActivityInfo.CONFIG_SCREEN_SIZE; 1106 } 1107 if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED 1108 && smallestScreenWidthDp != delta.smallestScreenWidthDp) { 1109 changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; 1110 } 1111 if (delta.densityDpi != DENSITY_DPI_UNDEFINED 1112 && densityDpi != delta.densityDpi) { 1113 changed |= ActivityInfo.CONFIG_DENSITY; 1114 } 1115 1116 return changed; 1117 } 1118 1119 /** 1120 * Determine if a new resource needs to be loaded from the bit set of 1121 * configuration changes returned by {@link #updateFrom(Configuration)}. 1122 * 1123 * @param configChanges The mask of changes configurations as returned by 1124 * {@link #updateFrom(Configuration)}. 1125 * @param interestingChanges The configuration changes that the resource 1126 * can handled, as given in {@link android.util.TypedValue#changingConfigurations}. 1127 * 1128 * @return Return true if the resource needs to be loaded, else false. 1129 */ 1130 public static boolean needNewResources(int configChanges, int interestingChanges) { 1131 return (configChanges & (interestingChanges|ActivityInfo.CONFIG_FONT_SCALE)) != 0; 1132 } 1133 1134 /** 1135 * @hide Return true if the sequence of 'other' is better than this. Assumes 1136 * that 'this' is your current sequence and 'other' is a new one you have 1137 * received some how and want to compare with what you have. 1138 */ 1139 public boolean isOtherSeqNewer(Configuration other) { 1140 if (other == null) { 1141 // Sanity check. 1142 return false; 1143 } 1144 if (other.seq == 0) { 1145 // If the other sequence is not specified, then we must assume 1146 // it is newer since we don't know any better. 1147 return true; 1148 } 1149 if (seq == 0) { 1150 // If this sequence is not specified, then we also consider the 1151 // other is better. Yes we have a preference for other. Sue us. 1152 return true; 1153 } 1154 int diff = other.seq - seq; 1155 if (diff > 0x10000) { 1156 // If there has been a sufficiently large jump, assume the 1157 // sequence has wrapped around. 1158 return false; 1159 } 1160 return diff > 0; 1161 } 1162 1163 /** 1164 * Parcelable methods 1165 */ 1166 public int describeContents() { 1167 return 0; 1168 } 1169 1170 public void writeToParcel(Parcel dest, int flags) { 1171 dest.writeFloat(fontScale); 1172 dest.writeInt(mcc); 1173 dest.writeInt(mnc); 1174 1175 fixUpLocaleList(); 1176 final int localeListSize = mLocaleList.size(); 1177 dest.writeInt(localeListSize); 1178 for (int i = 0; i < localeListSize; ++i) { 1179 final Locale l = mLocaleList.get(i); 1180 dest.writeString(l.toLanguageTag()); 1181 } 1182 1183 if(userSetLocale) { 1184 dest.writeInt(1); 1185 } else { 1186 dest.writeInt(0); 1187 } 1188 dest.writeInt(touchscreen); 1189 dest.writeInt(keyboard); 1190 dest.writeInt(keyboardHidden); 1191 dest.writeInt(hardKeyboardHidden); 1192 dest.writeInt(navigation); 1193 dest.writeInt(navigationHidden); 1194 dest.writeInt(orientation); 1195 dest.writeInt(screenLayout); 1196 dest.writeInt(uiMode); 1197 dest.writeInt(screenWidthDp); 1198 dest.writeInt(screenHeightDp); 1199 dest.writeInt(smallestScreenWidthDp); 1200 dest.writeInt(densityDpi); 1201 dest.writeInt(compatScreenWidthDp); 1202 dest.writeInt(compatScreenHeightDp); 1203 dest.writeInt(compatSmallestScreenWidthDp); 1204 dest.writeInt(seq); 1205 } 1206 1207 public void readFromParcel(Parcel source) { 1208 fontScale = source.readFloat(); 1209 mcc = source.readInt(); 1210 mnc = source.readInt(); 1211 1212 final int localeListSize = source.readInt(); 1213 final Locale[] localeArray = new Locale[localeListSize]; 1214 for (int i = 0; i < localeListSize; ++i) { 1215 localeArray[i] = Locale.forLanguageTag(source.readString()); 1216 } 1217 mLocaleList = new LocaleList(localeArray); 1218 locale = mLocaleList.getPrimary(); 1219 1220 userSetLocale = (source.readInt()==1); 1221 touchscreen = source.readInt(); 1222 keyboard = source.readInt(); 1223 keyboardHidden = source.readInt(); 1224 hardKeyboardHidden = source.readInt(); 1225 navigation = source.readInt(); 1226 navigationHidden = source.readInt(); 1227 orientation = source.readInt(); 1228 screenLayout = source.readInt(); 1229 uiMode = source.readInt(); 1230 screenWidthDp = source.readInt(); 1231 screenHeightDp = source.readInt(); 1232 smallestScreenWidthDp = source.readInt(); 1233 densityDpi = source.readInt(); 1234 compatScreenWidthDp = source.readInt(); 1235 compatScreenHeightDp = source.readInt(); 1236 compatSmallestScreenWidthDp = source.readInt(); 1237 seq = source.readInt(); 1238 } 1239 1240 public static final Parcelable.Creator<Configuration> CREATOR 1241 = new Parcelable.Creator<Configuration>() { 1242 public Configuration createFromParcel(Parcel source) { 1243 return new Configuration(source); 1244 } 1245 1246 public Configuration[] newArray(int size) { 1247 return new Configuration[size]; 1248 } 1249 }; 1250 1251 /** 1252 * Construct this Configuration object, reading from the Parcel. 1253 */ 1254 private Configuration(Parcel source) { 1255 readFromParcel(source); 1256 } 1257 1258 public int compareTo(Configuration that) { 1259 int n; 1260 float a = this.fontScale; 1261 float b = that.fontScale; 1262 if (a < b) return -1; 1263 if (a > b) return 1; 1264 n = this.mcc - that.mcc; 1265 if (n != 0) return n; 1266 n = this.mnc - that.mnc; 1267 if (n != 0) return n; 1268 1269 fixUpLocaleList(); 1270 that.fixUpLocaleList(); 1271 // for backward compatibility, we consider an empty locale list to be greater 1272 // than any non-empty locale list. 1273 if (this.mLocaleList.isEmpty()) { 1274 if (!that.mLocaleList.isEmpty()) return 1; 1275 } else if (that.mLocaleList.isEmpty()) { 1276 return -1; 1277 } else { 1278 final int minSize = Math.min(this.mLocaleList.size(), that.mLocaleList.size()); 1279 for (int i = 0; i < minSize; ++i) { 1280 final Locale thisLocale = this.mLocaleList.get(i); 1281 final Locale thatLocale = that.mLocaleList.get(i); 1282 n = thisLocale.getLanguage().compareTo(thatLocale.getLanguage()); 1283 if (n != 0) return n; 1284 n = thisLocale.getCountry().compareTo(thatLocale.getCountry()); 1285 if (n != 0) return n; 1286 n = thisLocale.getVariant().compareTo(thatLocale.getVariant()); 1287 if (n != 0) return n; 1288 n = thisLocale.toLanguageTag().compareTo(thatLocale.toLanguageTag()); 1289 if (n != 0) return n; 1290 } 1291 n = this.mLocaleList.size() - that.mLocaleList.size(); 1292 if (n != 0) return n; 1293 } 1294 1295 n = this.touchscreen - that.touchscreen; 1296 if (n != 0) return n; 1297 n = this.keyboard - that.keyboard; 1298 if (n != 0) return n; 1299 n = this.keyboardHidden - that.keyboardHidden; 1300 if (n != 0) return n; 1301 n = this.hardKeyboardHidden - that.hardKeyboardHidden; 1302 if (n != 0) return n; 1303 n = this.navigation - that.navigation; 1304 if (n != 0) return n; 1305 n = this.navigationHidden - that.navigationHidden; 1306 if (n != 0) return n; 1307 n = this.orientation - that.orientation; 1308 if (n != 0) return n; 1309 n = this.screenLayout - that.screenLayout; 1310 if (n != 0) return n; 1311 n = this.uiMode - that.uiMode; 1312 if (n != 0) return n; 1313 n = this.screenWidthDp - that.screenWidthDp; 1314 if (n != 0) return n; 1315 n = this.screenHeightDp - that.screenHeightDp; 1316 if (n != 0) return n; 1317 n = this.smallestScreenWidthDp - that.smallestScreenWidthDp; 1318 if (n != 0) return n; 1319 n = this.densityDpi - that.densityDpi; 1320 //if (n != 0) return n; 1321 return n; 1322 } 1323 1324 public boolean equals(Configuration that) { 1325 if (that == null) return false; 1326 if (that == this) return true; 1327 return this.compareTo(that) == 0; 1328 } 1329 1330 public boolean equals(Object that) { 1331 try { 1332 return equals((Configuration)that); 1333 } catch (ClassCastException e) { 1334 } 1335 return false; 1336 } 1337 1338 public int hashCode() { 1339 int result = 17; 1340 result = 31 * result + Float.floatToIntBits(fontScale); 1341 result = 31 * result + mcc; 1342 result = 31 * result + mnc; 1343 result = 31 * result + mLocaleList.hashCode(); 1344 result = 31 * result + touchscreen; 1345 result = 31 * result + keyboard; 1346 result = 31 * result + keyboardHidden; 1347 result = 31 * result + hardKeyboardHidden; 1348 result = 31 * result + navigation; 1349 result = 31 * result + navigationHidden; 1350 result = 31 * result + orientation; 1351 result = 31 * result + screenLayout; 1352 result = 31 * result + uiMode; 1353 result = 31 * result + screenWidthDp; 1354 result = 31 * result + screenHeightDp; 1355 result = 31 * result + smallestScreenWidthDp; 1356 result = 31 * result + densityDpi; 1357 return result; 1358 } 1359 1360 /** 1361 * Get the locale list. This is the preferred way for getting the locales (instead of using 1362 * the direct accessor to {@link #locale}, which would only provide the primary locale). 1363 * 1364 * @return The locale list. 1365 */ 1366 public LocaleList getLocales() { 1367 fixUpLocaleList(); 1368 return mLocaleList; 1369 } 1370 1371 /** 1372 * Set the locale list. This is the preferred way for setting up the locales (instead of using 1373 * the direct accessor or {@link #setLocale(Locale)}). This will also set the layout direction 1374 * according to the first locale in the list. 1375 * 1376 * Note that the layout direction will always come from the first locale in the locale list, 1377 * even if the locale is not supported by the resources (the resources may only support 1378 * another locale further down the list which has a different direction). 1379 * 1380 * @param locales The locale list. If null, an empty LocaleList will be assigned. 1381 */ 1382 public void setLocales(@Nullable LocaleList locales) { 1383 mLocaleList = locales == null ? LocaleList.getEmptyLocaleList() : locales; 1384 locale = mLocaleList.getPrimary(); 1385 setLayoutDirection(locale); 1386 } 1387 1388 /** 1389 * Set the locale list to a list of just one locale. This will also set the layout direction 1390 * according to the locale. 1391 * 1392 * Note that after this is run, calling <code>.equals()</code> on the input locale and the 1393 * {@link #locale} attribute would return <code>true</code> if they are not null, but there is 1394 * no guarantee that they would be the same object. 1395 * 1396 * See also the note about layout direction in {@link #setLocales(LocaleList)}. 1397 * 1398 * @param loc The locale. Can be null. 1399 */ 1400 public void setLocale(@Nullable Locale loc) { 1401 setLocales(new LocaleList(loc)); 1402 } 1403 1404 /** 1405 * Return the layout direction. Will be either {@link View#LAYOUT_DIRECTION_LTR} or 1406 * {@link View#LAYOUT_DIRECTION_RTL}. 1407 * 1408 * @return Returns {@link View#LAYOUT_DIRECTION_RTL} if the configuration 1409 * is {@link #SCREENLAYOUT_LAYOUTDIR_RTL}, otherwise {@link View#LAYOUT_DIRECTION_LTR}. 1410 */ 1411 public int getLayoutDirection() { 1412 return (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK) == SCREENLAYOUT_LAYOUTDIR_RTL 1413 ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR; 1414 } 1415 1416 /** 1417 * Set the layout direction from a Locale. 1418 * 1419 * @param loc The Locale. If null will set the layout direction to 1420 * {@link View#LAYOUT_DIRECTION_LTR}. If not null will set it to the layout direction 1421 * corresponding to the Locale. 1422 * 1423 * @see View#LAYOUT_DIRECTION_LTR 1424 * @see View#LAYOUT_DIRECTION_RTL 1425 */ 1426 public void setLayoutDirection(Locale loc) { 1427 // There is a "1" difference between the configuration values for 1428 // layout direction and View constants for layout direction, just add "1". 1429 final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(loc); 1430 screenLayout = (screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK)| 1431 (layoutDirection << SCREENLAYOUT_LAYOUTDIR_SHIFT); 1432 } 1433 1434 private static int getScreenLayoutNoDirection(int screenLayout) { 1435 return screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK; 1436 } 1437 1438 /** 1439 * Return whether the screen has a round shape. Apps may choose to change styling based 1440 * on this property, such as the alignment or layout of text or informational icons. 1441 * 1442 * @return true if the screen is rounded, false otherwise 1443 */ 1444 public boolean isScreenRound() { 1445 return (screenLayout & SCREENLAYOUT_ROUND_MASK) == SCREENLAYOUT_ROUND_YES; 1446 } 1447 1448 /** 1449 * 1450 * @hide 1451 */ 1452 public static String localeToResourceQualifier(Locale loc) { 1453 StringBuilder sb = new StringBuilder(); 1454 boolean l = (loc.getLanguage().length() != 0); 1455 boolean c = (loc.getCountry().length() != 0); 1456 boolean s = (loc.getScript().length() != 0); 1457 boolean v = (loc.getVariant().length() != 0); 1458 // TODO: take script and extensions into account 1459 if (l) { 1460 sb.append(loc.getLanguage()); 1461 if (c) { 1462 sb.append("-r").append(loc.getCountry()); 1463 if (s) { 1464 sb.append("-s").append(loc.getScript()); 1465 if (v) { 1466 sb.append("-v").append(loc.getVariant()); 1467 } 1468 } 1469 } 1470 } 1471 return sb.toString(); 1472 } 1473 1474 1475 /** 1476 * Returns a string representation of the configuration that can be parsed 1477 * by build tools (like AAPT). 1478 * 1479 * @hide 1480 */ 1481 public static String resourceQualifierString(Configuration config) { 1482 ArrayList<String> parts = new ArrayList<String>(); 1483 1484 if (config.mcc != 0) { 1485 parts.add("mcc" + config.mcc); 1486 if (config.mnc != 0) { 1487 parts.add("mnc" + config.mnc); 1488 } 1489 } 1490 1491 // TODO: send the whole locale list 1492 if (config.locale != null && !config.locale.getLanguage().isEmpty()) { 1493 parts.add(localeToResourceQualifier(config.locale)); 1494 } 1495 1496 switch (config.screenLayout & Configuration.SCREENLAYOUT_LAYOUTDIR_MASK) { 1497 case Configuration.SCREENLAYOUT_LAYOUTDIR_LTR: 1498 parts.add("ldltr"); 1499 break; 1500 case Configuration.SCREENLAYOUT_LAYOUTDIR_RTL: 1501 parts.add("ldrtl"); 1502 break; 1503 default: 1504 break; 1505 } 1506 1507 if (config.smallestScreenWidthDp != 0) { 1508 parts.add("sw" + config.smallestScreenWidthDp + "dp"); 1509 } 1510 1511 if (config.screenWidthDp != 0) { 1512 parts.add("w" + config.screenWidthDp + "dp"); 1513 } 1514 1515 if (config.screenHeightDp != 0) { 1516 parts.add("h" + config.screenHeightDp + "dp"); 1517 } 1518 1519 switch (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) { 1520 case Configuration.SCREENLAYOUT_SIZE_SMALL: 1521 parts.add("small"); 1522 break; 1523 case Configuration.SCREENLAYOUT_SIZE_NORMAL: 1524 parts.add("normal"); 1525 break; 1526 case Configuration.SCREENLAYOUT_SIZE_LARGE: 1527 parts.add("large"); 1528 break; 1529 case Configuration.SCREENLAYOUT_SIZE_XLARGE: 1530 parts.add("xlarge"); 1531 break; 1532 default: 1533 break; 1534 } 1535 1536 switch (config.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK) { 1537 case Configuration.SCREENLAYOUT_LONG_YES: 1538 parts.add("long"); 1539 break; 1540 case Configuration.SCREENLAYOUT_LONG_NO: 1541 parts.add("notlong"); 1542 break; 1543 default: 1544 break; 1545 } 1546 1547 switch (config.screenLayout & Configuration.SCREENLAYOUT_ROUND_MASK) { 1548 case Configuration.SCREENLAYOUT_ROUND_YES: 1549 parts.add("round"); 1550 break; 1551 case Configuration.SCREENLAYOUT_ROUND_NO: 1552 parts.add("notround"); 1553 break; 1554 default: 1555 break; 1556 } 1557 1558 switch (config.orientation) { 1559 case Configuration.ORIENTATION_LANDSCAPE: 1560 parts.add("land"); 1561 break; 1562 case Configuration.ORIENTATION_PORTRAIT: 1563 parts.add("port"); 1564 break; 1565 default: 1566 break; 1567 } 1568 1569 switch (config.uiMode & Configuration.UI_MODE_TYPE_MASK) { 1570 case Configuration.UI_MODE_TYPE_APPLIANCE: 1571 parts.add("appliance"); 1572 break; 1573 case Configuration.UI_MODE_TYPE_DESK: 1574 parts.add("desk"); 1575 break; 1576 case Configuration.UI_MODE_TYPE_TELEVISION: 1577 parts.add("television"); 1578 break; 1579 case Configuration.UI_MODE_TYPE_CAR: 1580 parts.add("car"); 1581 break; 1582 case Configuration.UI_MODE_TYPE_WATCH: 1583 parts.add("watch"); 1584 break; 1585 default: 1586 break; 1587 } 1588 1589 switch (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) { 1590 case Configuration.UI_MODE_NIGHT_YES: 1591 parts.add("night"); 1592 break; 1593 case Configuration.UI_MODE_NIGHT_NO: 1594 parts.add("notnight"); 1595 break; 1596 default: 1597 break; 1598 } 1599 1600 switch (config.densityDpi) { 1601 case DENSITY_DPI_UNDEFINED: 1602 break; 1603 case 120: 1604 parts.add("ldpi"); 1605 break; 1606 case 160: 1607 parts.add("mdpi"); 1608 break; 1609 case 213: 1610 parts.add("tvdpi"); 1611 break; 1612 case 240: 1613 parts.add("hdpi"); 1614 break; 1615 case 320: 1616 parts.add("xhdpi"); 1617 break; 1618 case 480: 1619 parts.add("xxhdpi"); 1620 break; 1621 case 640: 1622 parts.add("xxxhdpi"); 1623 break; 1624 case DENSITY_DPI_ANY: 1625 parts.add("anydpi"); 1626 break; 1627 case DENSITY_DPI_NONE: 1628 parts.add("nodpi"); 1629 default: 1630 parts.add(config.densityDpi + "dpi"); 1631 break; 1632 } 1633 1634 switch (config.touchscreen) { 1635 case Configuration.TOUCHSCREEN_NOTOUCH: 1636 parts.add("notouch"); 1637 break; 1638 case Configuration.TOUCHSCREEN_FINGER: 1639 parts.add("finger"); 1640 break; 1641 default: 1642 break; 1643 } 1644 1645 switch (config.keyboardHidden) { 1646 case Configuration.KEYBOARDHIDDEN_NO: 1647 parts.add("keysexposed"); 1648 break; 1649 case Configuration.KEYBOARDHIDDEN_YES: 1650 parts.add("keyshidden"); 1651 break; 1652 case Configuration.KEYBOARDHIDDEN_SOFT: 1653 parts.add("keyssoft"); 1654 break; 1655 default: 1656 break; 1657 } 1658 1659 switch (config.keyboard) { 1660 case Configuration.KEYBOARD_NOKEYS: 1661 parts.add("nokeys"); 1662 break; 1663 case Configuration.KEYBOARD_QWERTY: 1664 parts.add("qwerty"); 1665 break; 1666 case Configuration.KEYBOARD_12KEY: 1667 parts.add("12key"); 1668 break; 1669 default: 1670 break; 1671 } 1672 1673 switch (config.navigationHidden) { 1674 case Configuration.NAVIGATIONHIDDEN_NO: 1675 parts.add("navexposed"); 1676 break; 1677 case Configuration.NAVIGATIONHIDDEN_YES: 1678 parts.add("navhidden"); 1679 break; 1680 default: 1681 break; 1682 } 1683 1684 switch (config.navigation) { 1685 case Configuration.NAVIGATION_NONAV: 1686 parts.add("nonav"); 1687 break; 1688 case Configuration.NAVIGATION_DPAD: 1689 parts.add("dpad"); 1690 break; 1691 case Configuration.NAVIGATION_TRACKBALL: 1692 parts.add("trackball"); 1693 break; 1694 case Configuration.NAVIGATION_WHEEL: 1695 parts.add("wheel"); 1696 break; 1697 default: 1698 break; 1699 } 1700 1701 parts.add("v" + Build.VERSION.RESOURCES_SDK_INT); 1702 return TextUtils.join("-", parts); 1703 } 1704 1705 /** 1706 * Generate a delta Configuration between <code>base</code> and <code>change</code>. The 1707 * resulting delta can be used with {@link #updateFrom(Configuration)}. 1708 * <p /> 1709 * Caveat: If the any of the Configuration's members becomes undefined, then 1710 * {@link #updateFrom(Configuration)} will treat it as a no-op and not update that member. 1711 * 1712 * This is fine for device configurations as no member is ever undefined. 1713 * {@hide} 1714 */ 1715 public static Configuration generateDelta(Configuration base, Configuration change) { 1716 final Configuration delta = new Configuration(); 1717 if (base.fontScale != change.fontScale) { 1718 delta.fontScale = change.fontScale; 1719 } 1720 1721 if (base.mcc != change.mcc) { 1722 delta.mcc = change.mcc; 1723 } 1724 1725 if (base.mnc != change.mnc) { 1726 delta.mnc = change.mnc; 1727 } 1728 1729 base.fixUpLocaleList(); 1730 change.fixUpLocaleList(); 1731 if (!base.mLocaleList.equals(change.mLocaleList)) { 1732 delta.mLocaleList = change.mLocaleList; 1733 delta.locale = change.locale; 1734 } 1735 1736 if (base.touchscreen != change.touchscreen) { 1737 delta.touchscreen = change.touchscreen; 1738 } 1739 1740 if (base.keyboard != change.keyboard) { 1741 delta.keyboard = change.keyboard; 1742 } 1743 1744 if (base.keyboardHidden != change.keyboardHidden) { 1745 delta.keyboardHidden = change.keyboardHidden; 1746 } 1747 1748 if (base.navigation != change.navigation) { 1749 delta.navigation = change.navigation; 1750 } 1751 1752 if (base.navigationHidden != change.navigationHidden) { 1753 delta.navigationHidden = change.navigationHidden; 1754 } 1755 1756 if (base.orientation != change.orientation) { 1757 delta.orientation = change.orientation; 1758 } 1759 1760 if ((base.screenLayout & SCREENLAYOUT_SIZE_MASK) != 1761 (change.screenLayout & SCREENLAYOUT_SIZE_MASK)) { 1762 delta.screenLayout |= change.screenLayout & SCREENLAYOUT_SIZE_MASK; 1763 } 1764 1765 if ((base.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK) != 1766 (change.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) { 1767 delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK; 1768 } 1769 1770 if ((base.screenLayout & SCREENLAYOUT_LONG_MASK) != 1771 (change.screenLayout & SCREENLAYOUT_LONG_MASK)) { 1772 delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LONG_MASK; 1773 } 1774 1775 if ((base.screenLayout & SCREENLAYOUT_ROUND_MASK) != 1776 (change.screenLayout & SCREENLAYOUT_ROUND_MASK)) { 1777 delta.screenLayout |= change.screenLayout & SCREENLAYOUT_ROUND_MASK; 1778 } 1779 1780 if ((base.uiMode & UI_MODE_TYPE_MASK) != (change.uiMode & UI_MODE_TYPE_MASK)) { 1781 delta.uiMode |= change.uiMode & UI_MODE_TYPE_MASK; 1782 } 1783 1784 if ((base.uiMode & UI_MODE_NIGHT_MASK) != (change.uiMode & UI_MODE_NIGHT_MASK)) { 1785 delta.uiMode |= change.uiMode & UI_MODE_NIGHT_MASK; 1786 } 1787 1788 if (base.screenWidthDp != change.screenWidthDp) { 1789 delta.screenWidthDp = change.screenWidthDp; 1790 } 1791 1792 if (base.screenHeightDp != change.screenHeightDp) { 1793 delta.screenHeightDp = change.screenHeightDp; 1794 } 1795 1796 if (base.smallestScreenWidthDp != change.smallestScreenWidthDp) { 1797 delta.smallestScreenWidthDp = change.smallestScreenWidthDp; 1798 } 1799 1800 if (base.densityDpi != change.densityDpi) { 1801 delta.densityDpi = change.densityDpi; 1802 } 1803 return delta; 1804 } 1805 1806 private static final String XML_ATTR_FONT_SCALE = "fs"; 1807 private static final String XML_ATTR_MCC = "mcc"; 1808 private static final String XML_ATTR_MNC = "mnc"; 1809 private static final String XML_ATTR_LOCALES = "locales"; 1810 private static final String XML_ATTR_TOUCHSCREEN = "touch"; 1811 private static final String XML_ATTR_KEYBOARD = "key"; 1812 private static final String XML_ATTR_KEYBOARD_HIDDEN = "keyHid"; 1813 private static final String XML_ATTR_HARD_KEYBOARD_HIDDEN = "hardKeyHid"; 1814 private static final String XML_ATTR_NAVIGATION = "nav"; 1815 private static final String XML_ATTR_NAVIGATION_HIDDEN = "navHid"; 1816 private static final String XML_ATTR_ORIENTATION = "ori"; 1817 private static final String XML_ATTR_SCREEN_LAYOUT = "scrLay"; 1818 private static final String XML_ATTR_UI_MODE = "ui"; 1819 private static final String XML_ATTR_SCREEN_WIDTH = "width"; 1820 private static final String XML_ATTR_SCREEN_HEIGHT = "height"; 1821 private static final String XML_ATTR_SMALLEST_WIDTH = "sw"; 1822 private static final String XML_ATTR_DENSITY = "density"; 1823 1824 /** 1825 * Reads the attributes corresponding to Configuration member fields from the Xml parser. 1826 * The parser is expected to be on a tag which has Configuration attributes. 1827 * 1828 * @param parser The Xml parser from which to read attributes. 1829 * @param configOut The Configuration to populate from the Xml attributes. 1830 * {@hide} 1831 */ 1832 public static void readXmlAttrs(XmlPullParser parser, Configuration configOut) 1833 throws XmlPullParserException, IOException { 1834 configOut.fontScale = Float.intBitsToFloat( 1835 XmlUtils.readIntAttribute(parser, XML_ATTR_FONT_SCALE, 0)); 1836 configOut.mcc = XmlUtils.readIntAttribute(parser, XML_ATTR_MCC, 0); 1837 configOut.mnc = XmlUtils.readIntAttribute(parser, XML_ATTR_MNC, 0); 1838 1839 final String localesStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALES); 1840 configOut.mLocaleList = LocaleList.forLanguageTags(localesStr); 1841 configOut.locale = configOut.mLocaleList.getPrimary(); 1842 1843 configOut.touchscreen = XmlUtils.readIntAttribute(parser, XML_ATTR_TOUCHSCREEN, 1844 TOUCHSCREEN_UNDEFINED); 1845 configOut.keyboard = XmlUtils.readIntAttribute(parser, XML_ATTR_KEYBOARD, 1846 KEYBOARD_UNDEFINED); 1847 configOut.keyboardHidden = XmlUtils.readIntAttribute(parser, XML_ATTR_KEYBOARD_HIDDEN, 1848 KEYBOARDHIDDEN_UNDEFINED); 1849 configOut.hardKeyboardHidden = 1850 XmlUtils.readIntAttribute(parser, XML_ATTR_HARD_KEYBOARD_HIDDEN, 1851 HARDKEYBOARDHIDDEN_UNDEFINED); 1852 configOut.navigation = XmlUtils.readIntAttribute(parser, XML_ATTR_NAVIGATION, 1853 NAVIGATION_UNDEFINED); 1854 configOut.navigationHidden = XmlUtils.readIntAttribute(parser, XML_ATTR_NAVIGATION_HIDDEN, 1855 NAVIGATIONHIDDEN_UNDEFINED); 1856 configOut.orientation = XmlUtils.readIntAttribute(parser, XML_ATTR_ORIENTATION, 1857 ORIENTATION_UNDEFINED); 1858 configOut.screenLayout = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_LAYOUT, 1859 SCREENLAYOUT_UNDEFINED); 1860 configOut.uiMode = XmlUtils.readIntAttribute(parser, XML_ATTR_UI_MODE, 0); 1861 configOut.screenWidthDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_WIDTH, 1862 SCREEN_WIDTH_DP_UNDEFINED); 1863 configOut.screenHeightDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_HEIGHT, 1864 SCREEN_HEIGHT_DP_UNDEFINED); 1865 configOut.smallestScreenWidthDp = 1866 XmlUtils.readIntAttribute(parser, XML_ATTR_SMALLEST_WIDTH, 1867 SMALLEST_SCREEN_WIDTH_DP_UNDEFINED); 1868 configOut.densityDpi = XmlUtils.readIntAttribute(parser, XML_ATTR_DENSITY, 1869 DENSITY_DPI_UNDEFINED); 1870 } 1871 1872 1873 /** 1874 * Writes the Configuration's member fields as attributes into the XmlSerializer. 1875 * The serializer is expected to have already started a tag so that attributes can be 1876 * immediately written. 1877 * 1878 * @param xml The serializer to which to write the attributes. 1879 * @param config The Configuration whose member fields to write. 1880 * {@hide} 1881 */ 1882 public static void writeXmlAttrs(XmlSerializer xml, Configuration config) throws IOException { 1883 XmlUtils.writeIntAttribute(xml, XML_ATTR_FONT_SCALE, 1884 Float.floatToIntBits(config.fontScale)); 1885 if (config.mcc != 0) { 1886 XmlUtils.writeIntAttribute(xml, XML_ATTR_MCC, config.mcc); 1887 } 1888 if (config.mnc != 0) { 1889 XmlUtils.writeIntAttribute(xml, XML_ATTR_MNC, config.mnc); 1890 } 1891 config.fixUpLocaleList(); 1892 if (!config.mLocaleList.isEmpty()) { 1893 XmlUtils.writeStringAttribute(xml, XML_ATTR_LOCALES, config.mLocaleList.toLanguageTags()); 1894 } 1895 if (config.touchscreen != TOUCHSCREEN_UNDEFINED) { 1896 XmlUtils.writeIntAttribute(xml, XML_ATTR_TOUCHSCREEN, config.touchscreen); 1897 } 1898 if (config.keyboard != KEYBOARD_UNDEFINED) { 1899 XmlUtils.writeIntAttribute(xml, XML_ATTR_KEYBOARD, config.keyboard); 1900 } 1901 if (config.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED) { 1902 XmlUtils.writeIntAttribute(xml, XML_ATTR_KEYBOARD_HIDDEN, config.keyboardHidden); 1903 } 1904 if (config.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED) { 1905 XmlUtils.writeIntAttribute(xml, XML_ATTR_HARD_KEYBOARD_HIDDEN, 1906 config.hardKeyboardHidden); 1907 } 1908 if (config.navigation != NAVIGATION_UNDEFINED) { 1909 XmlUtils.writeIntAttribute(xml, XML_ATTR_NAVIGATION, config.navigation); 1910 } 1911 if (config.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED) { 1912 XmlUtils.writeIntAttribute(xml, XML_ATTR_NAVIGATION_HIDDEN, config.navigationHidden); 1913 } 1914 if (config.orientation != ORIENTATION_UNDEFINED) { 1915 XmlUtils.writeIntAttribute(xml, XML_ATTR_ORIENTATION, config.orientation); 1916 } 1917 if (config.screenLayout != SCREENLAYOUT_UNDEFINED) { 1918 XmlUtils.writeIntAttribute(xml, XML_ATTR_SCREEN_LAYOUT, config.screenLayout); 1919 } 1920 if (config.uiMode != 0) { 1921 XmlUtils.writeIntAttribute(xml, XML_ATTR_UI_MODE, config.uiMode); 1922 } 1923 if (config.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) { 1924 XmlUtils.writeIntAttribute(xml, XML_ATTR_SCREEN_WIDTH, config.screenWidthDp); 1925 } 1926 if (config.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) { 1927 XmlUtils.writeIntAttribute(xml, XML_ATTR_SCREEN_HEIGHT, config.screenHeightDp); 1928 } 1929 if (config.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { 1930 XmlUtils.writeIntAttribute(xml, XML_ATTR_SMALLEST_WIDTH, config.smallestScreenWidthDp); 1931 } 1932 if (config.densityDpi != DENSITY_DPI_UNDEFINED) { 1933 XmlUtils.writeIntAttribute(xml, XML_ATTR_DENSITY, config.densityDpi); 1934 } 1935 } 1936} 1937