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