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