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