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 static android.content.ConfigurationProto.COLOR_MODE; 20 import static android.content.ConfigurationProto.DENSITY_DPI; 21 import static android.content.ConfigurationProto.FONT_SCALE; 22 import static android.content.ConfigurationProto.FONT_WEIGHT_ADJUSTMENT; 23 import static android.content.ConfigurationProto.GRAMMATICAL_GENDER; 24 import static android.content.ConfigurationProto.HARD_KEYBOARD_HIDDEN; 25 import static android.content.ConfigurationProto.KEYBOARD; 26 import static android.content.ConfigurationProto.KEYBOARD_HIDDEN; 27 import static android.content.ConfigurationProto.LOCALES; 28 import static android.content.ConfigurationProto.LOCALE_LIST; 29 import static android.content.ConfigurationProto.MCC; 30 import static android.content.ConfigurationProto.MNC; 31 import static android.content.ConfigurationProto.NAVIGATION; 32 import static android.content.ConfigurationProto.NAVIGATION_HIDDEN; 33 import static android.content.ConfigurationProto.ORIENTATION; 34 import static android.content.ConfigurationProto.SCREEN_HEIGHT_DP; 35 import static android.content.ConfigurationProto.SCREEN_LAYOUT; 36 import static android.content.ConfigurationProto.SCREEN_WIDTH_DP; 37 import static android.content.ConfigurationProto.SMALLEST_SCREEN_WIDTH_DP; 38 import static android.content.ConfigurationProto.TOUCHSCREEN; 39 import static android.content.ConfigurationProto.UI_MODE; 40 import static android.content.ConfigurationProto.WINDOW_CONFIGURATION; 41 import static android.content.ResourcesConfigurationProto.CONFIGURATION; 42 import static android.content.ResourcesConfigurationProto.SCREEN_HEIGHT_PX; 43 import static android.content.ResourcesConfigurationProto.SCREEN_WIDTH_PX; 44 import static android.content.ResourcesConfigurationProto.SDK_VERSION; 45 46 import android.annotation.IntDef; 47 import android.annotation.NonNull; 48 import android.annotation.Nullable; 49 import android.annotation.TestApi; 50 import android.app.GrammaticalInflectionManager; 51 import android.app.WindowConfiguration; 52 import android.compat.annotation.UnsupportedAppUsage; 53 import android.content.LocaleProto; 54 import android.content.pm.ActivityInfo; 55 import android.content.pm.ActivityInfo.Config; 56 import android.graphics.Typeface; 57 import android.os.Build; 58 import android.os.LocaleList; 59 import android.os.Parcel; 60 import android.os.Parcelable; 61 import android.text.TextUtils; 62 import android.util.DisplayMetrics; 63 import android.util.Slog; 64 import android.util.proto.ProtoInputStream; 65 import android.util.proto.ProtoOutputStream; 66 import android.util.proto.WireTypeMismatchException; 67 import android.view.View; 68 69 import com.android.internal.util.XmlUtils; 70 71 import org.xmlpull.v1.XmlPullParser; 72 import org.xmlpull.v1.XmlPullParserException; 73 74 import java.io.IOException; 75 import java.lang.annotation.Retention; 76 import java.lang.annotation.RetentionPolicy; 77 import java.util.ArrayList; 78 import java.util.IllformedLocaleException; 79 import java.util.List; 80 import java.util.Locale; 81 82 /** 83 * This class describes all device configuration information that can 84 * impact the resources the application retrieves. This includes both 85 * user-specified configuration options (locale list and scaling) as well 86 * as device configurations (such as input modes, screen size and screen orientation). 87 * <p>You can acquire this object from {@link Resources}, using {@link 88 * Resources#getConfiguration}. Thus, from an activity, you can get it by chaining the request 89 * with {@link android.app.Activity#getResources}:</p> 90 * <pre>Configuration config = getResources().getConfiguration();</pre> 91 */ 92 public final class Configuration implements Parcelable, Comparable<Configuration> { 93 /** @hide */ 94 public static final Configuration EMPTY = new Configuration(); 95 96 private static final String TAG = "Configuration"; 97 98 /** 99 * Current user preference for the scaling factor for fonts, relative 100 * to the base density scaling. 101 * 102 * <p>Note: Please do not use this to hardcode font size equations. The equation for font 103 * scaling is now non-linear; this coefficient is no longer used as a direct multiplier to 104 * determine font size. It exists for informational purposes only. 105 * 106 * <p>Please use {@link android.util.TypedValue#applyDimension(int, float, DisplayMetrics)} or 107 * {@link android.util.TypedValue#deriveDimension(int, float, DisplayMetrics)} to convert 108 * between scaled font size dimensions and pixels. 109 */ 110 public float fontScale; 111 112 /** 113 * IMSI MCC (Mobile Country Code), corresponding to 114 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mcc</a> 115 * resource qualifier. 0 if undefined. 116 */ 117 public int mcc; 118 119 /** 120 * IMSI MNC (Mobile Network Code), corresponding to 121 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mnc</a> 122 * resource qualifier. 0 if undefined. Note that the actual MNC may be 0; in order to check 123 * for this use the {@link #MNC_ZERO} symbol. 124 */ 125 public int mnc; 126 127 /** 128 * Constant used to to represent MNC (Mobile Network Code) zero. 129 * 0 cannot be used, since it is used to represent an undefined MNC. 130 */ 131 public static final int MNC_ZERO = 0xffff; 132 133 /** 134 * Current user preference for the locale, corresponding to 135 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a> 136 * resource qualifier. 137 * 138 * @deprecated Do not set or read this directly. Use {@link #getLocales()} and 139 * {@link #setLocales(LocaleList)}. If only the primary locale is needed, 140 * <code>getLocales().get(0)</code> is now the preferred accessor. 141 */ 142 @Deprecated public Locale locale; 143 144 private LocaleList mLocaleList; 145 146 /** 147 * Locale should persist on setting. This is hidden because it is really 148 * questionable whether this is the right way to expose the functionality. 149 * @hide 150 */ 151 @UnsupportedAppUsage 152 public boolean userSetLocale; 153 154 /** 155 * Current user preference for the grammatical gender. 156 */ 157 @GrammaticalGender 158 private int mGrammaticalGender; 159 160 /** @hide */ 161 @IntDef(prefix = { "GRAMMATICAL_GENDER_" }, value = { 162 GRAMMATICAL_GENDER_NOT_SPECIFIED, 163 GRAMMATICAL_GENDER_NEUTRAL, 164 GRAMMATICAL_GENDER_FEMININE, 165 GRAMMATICAL_GENDER_MASCULINE, 166 }) 167 public @interface GrammaticalGender {} 168 169 /** 170 * Constant for grammatical gender: to indicate the user has not specified the terms 171 * of address for the application. 172 */ 173 public static final int GRAMMATICAL_GENDER_NOT_SPECIFIED = 0; 174 175 /** 176 * Constant for grammatical gender: to indicate the terms of address the user 177 * preferred in an application is neuter. 178 */ 179 public static final int GRAMMATICAL_GENDER_NEUTRAL = 1; 180 181 /** 182 * Constant for grammatical gender: to indicate the terms of address the user 183 * preferred in an application is feminine. 184 */ 185 public static final int GRAMMATICAL_GENDER_FEMININE = 2; 186 187 /** 188 * Constant for grammatical gender: to indicate the terms of address the user 189 * preferred in an application is masculine. 190 */ 191 public static final int GRAMMATICAL_GENDER_MASCULINE = 3; 192 193 /** Constant for {@link #colorMode}: bits that encode whether the screen is wide gamut. */ 194 public static final int COLOR_MODE_WIDE_COLOR_GAMUT_MASK = 0x3; 195 /** 196 * Constant for {@link #colorMode}: a {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} value 197 * indicating that it is unknown whether or not the screen is wide gamut. 198 */ 199 public static final int COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED = 0x0; 200 /** 201 * Constant for {@link #colorMode}: a {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} value 202 * indicating that the screen is not wide gamut. 203 * <p>Corresponds to the <code>-nowidecg</code> resource qualifier.</p> 204 */ 205 public static final int COLOR_MODE_WIDE_COLOR_GAMUT_NO = 0x1; 206 /** 207 * Constant for {@link #colorMode}: a {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} value 208 * indicating that the screen is wide gamut. 209 * <p>Corresponds to the <code>-widecg</code> resource qualifier.</p> 210 */ 211 public static final int COLOR_MODE_WIDE_COLOR_GAMUT_YES = 0x2; 212 213 /** Constant for {@link #colorMode}: bits that encode the dynamic range of the screen. */ 214 public static final int COLOR_MODE_HDR_MASK = 0xc; 215 /** Constant for {@link #colorMode}: bits shift to get the screen dynamic range. */ 216 public static final int COLOR_MODE_HDR_SHIFT = 2; 217 /** 218 * Constant for {@link #colorMode}: a {@link #COLOR_MODE_HDR_MASK} value 219 * indicating that it is unknown whether or not the screen is HDR. 220 */ 221 public static final int COLOR_MODE_HDR_UNDEFINED = 0x0; 222 /** 223 * Constant for {@link #colorMode}: a {@link #COLOR_MODE_HDR_MASK} value 224 * indicating that the screen is not HDR (low/standard dynamic range). 225 * <p>Corresponds to the <code>-lowdr</code> resource qualifier.</p> 226 */ 227 public static final int COLOR_MODE_HDR_NO = 0x1 << COLOR_MODE_HDR_SHIFT; 228 /** 229 * Constant for {@link #colorMode}: a {@link #COLOR_MODE_HDR_MASK} value 230 * indicating that the screen is HDR (dynamic range). 231 * <p>Corresponds to the <code>-highdr</code> resource qualifier.</p> 232 */ 233 public static final int COLOR_MODE_HDR_YES = 0x2 << COLOR_MODE_HDR_SHIFT; 234 235 /** Constant for {@link #colorMode}: a value indicating that the color mode is undefined */ 236 @SuppressWarnings("PointlessBitwiseExpression") 237 public static final int COLOR_MODE_UNDEFINED = COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED | 238 COLOR_MODE_HDR_UNDEFINED; 239 240 /** 241 * Bit mask of color capabilities of the screen. Currently there are two fields: 242 * <p>The {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} bits define the color gamut of 243 * the screen. They may be one of 244 * {@link #COLOR_MODE_WIDE_COLOR_GAMUT_NO} or {@link #COLOR_MODE_WIDE_COLOR_GAMUT_YES}.</p> 245 * 246 * <p>The {@link #COLOR_MODE_HDR_MASK} defines the dynamic range of the screen. They may be 247 * one of {@link #COLOR_MODE_HDR_NO} or {@link #COLOR_MODE_HDR_YES}.</p> 248 * 249 * <p>See <a href="{@docRoot}guide/practices/screens_support.html">Supporting 250 * Multiple Screens</a> for more information.</p> 251 */ 252 public int colorMode; 253 254 /** Constant for {@link #screenLayout}: bits that encode the size. */ 255 public static final int SCREENLAYOUT_SIZE_MASK = 0x0f; 256 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK} 257 * value indicating that no size has been set. */ 258 public static final int SCREENLAYOUT_SIZE_UNDEFINED = 0x00; 259 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK} 260 * value indicating the screen is at least approximately 320x426 dp units, 261 * corresponds to the 262 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">small</a> 263 * resource qualifier. 264 * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting 265 * Multiple Screens</a> for more information. */ 266 public static final int SCREENLAYOUT_SIZE_SMALL = 0x01; 267 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK} 268 * value indicating the screen is at least approximately 320x470 dp units, 269 * corresponds to the 270 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">normal</a> 271 * resource qualifier. 272 * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting 273 * Multiple Screens</a> for more information. */ 274 public static final int SCREENLAYOUT_SIZE_NORMAL = 0x02; 275 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK} 276 * value indicating the screen is at least approximately 480x640 dp units, 277 * corresponds to the 278 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">large</a> 279 * resource qualifier. 280 * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting 281 * Multiple Screens</a> for more information. */ 282 public static final int SCREENLAYOUT_SIZE_LARGE = 0x03; 283 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK} 284 * value indicating the screen is at least approximately 720x960 dp units, 285 * corresponds to the 286 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">xlarge</a> 287 * resource qualifier. 288 * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting 289 * Multiple Screens</a> for more information.*/ 290 public static final int SCREENLAYOUT_SIZE_XLARGE = 0x04; 291 292 /** Constant for {@link #screenLayout}: bits that encode the aspect ratio. */ 293 public static final int SCREENLAYOUT_LONG_MASK = 0x30; 294 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK} 295 * value indicating that no size has been set. */ 296 public static final int SCREENLAYOUT_LONG_UNDEFINED = 0x00; 297 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK} 298 * value that corresponds to the 299 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenAspectQualifier">notlong</a> 300 * resource qualifier. */ 301 public static final int SCREENLAYOUT_LONG_NO = 0x10; 302 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK} 303 * value that corresponds to the 304 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenAspectQualifier">long</a> 305 * resource qualifier. */ 306 public static final int SCREENLAYOUT_LONG_YES = 0x20; 307 308 /** Constant for {@link #screenLayout}: bits that encode the layout direction. */ 309 public static final int SCREENLAYOUT_LAYOUTDIR_MASK = 0xC0; 310 /** Constant for {@link #screenLayout}: bits shift to get the layout direction. */ 311 public static final int SCREENLAYOUT_LAYOUTDIR_SHIFT = 6; 312 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK} 313 * value indicating that no layout dir has been set. */ 314 public static final int SCREENLAYOUT_LAYOUTDIR_UNDEFINED = 0x00; 315 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK} 316 * value indicating that a layout dir has been set to LTR. */ 317 public static final int SCREENLAYOUT_LAYOUTDIR_LTR = 0x01 << SCREENLAYOUT_LAYOUTDIR_SHIFT; 318 /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK} 319 * value indicating that a layout dir has been set to RTL. */ 320 public static final int SCREENLAYOUT_LAYOUTDIR_RTL = 0x02 << SCREENLAYOUT_LAYOUTDIR_SHIFT; 321 322 /** Constant for {@link #screenLayout}: bits that encode roundness of the screen. */ 323 public static final int SCREENLAYOUT_ROUND_MASK = 0x300; 324 /** @hide Constant for {@link #screenLayout}: bit shift to get to screen roundness bits */ 325 public static final int SCREENLAYOUT_ROUND_SHIFT = 8; 326 /** 327 * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating 328 * that it is unknown whether or not the screen has a round shape. 329 */ 330 public static final int SCREENLAYOUT_ROUND_UNDEFINED = 0x00; 331 /** 332 * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating 333 * that the screen does not have a rounded shape. 334 */ 335 public static final int SCREENLAYOUT_ROUND_NO = 0x1 << SCREENLAYOUT_ROUND_SHIFT; 336 /** 337 * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating 338 * that the screen has a rounded shape. Corners may not be visible to the user; 339 * developers should pay special attention to the {@link android.view.WindowInsets} delivered 340 * to views for more information about ensuring content is not obscured. 341 * 342 * <p>Corresponds to the <code>-round</code> resource qualifier.</p> 343 */ 344 public static final int SCREENLAYOUT_ROUND_YES = 0x2 << SCREENLAYOUT_ROUND_SHIFT; 345 346 /** Constant for {@link #screenLayout}: a value indicating that screenLayout is undefined */ 347 public static final int SCREENLAYOUT_UNDEFINED = SCREENLAYOUT_SIZE_UNDEFINED | 348 SCREENLAYOUT_LONG_UNDEFINED | SCREENLAYOUT_LAYOUTDIR_UNDEFINED | 349 SCREENLAYOUT_ROUND_UNDEFINED; 350 351 /** 352 * Special flag we generate to indicate that the screen layout requires 353 * us to use a compatibility mode for apps that are not modern layout 354 * aware. 355 * @hide 356 */ 357 public static final int SCREENLAYOUT_COMPAT_NEEDED = 0x10000000; 358 359 /** 360 * Bit mask of overall layout of the screen. Currently there are four 361 * fields: 362 * <p>The {@link #SCREENLAYOUT_SIZE_MASK} bits define the overall size 363 * of the screen. They may be one of 364 * {@link #SCREENLAYOUT_SIZE_SMALL}, {@link #SCREENLAYOUT_SIZE_NORMAL}, 365 * {@link #SCREENLAYOUT_SIZE_LARGE}, or {@link #SCREENLAYOUT_SIZE_XLARGE}.</p> 366 * 367 * <p>The {@link #SCREENLAYOUT_LONG_MASK} defines whether the screen 368 * is wider/taller than normal. They may be one of 369 * {@link #SCREENLAYOUT_LONG_NO} or {@link #SCREENLAYOUT_LONG_YES}.</p> 370 * 371 * <p>The {@link #SCREENLAYOUT_LAYOUTDIR_MASK} defines whether the screen layout 372 * is either LTR or RTL. They may be one of 373 * {@link #SCREENLAYOUT_LAYOUTDIR_LTR} or {@link #SCREENLAYOUT_LAYOUTDIR_RTL}.</p> 374 * 375 * <p>The {@link #SCREENLAYOUT_ROUND_MASK} defines whether the screen has a rounded 376 * shape. They may be one of {@link #SCREENLAYOUT_ROUND_NO} or {@link #SCREENLAYOUT_ROUND_YES}. 377 * </p> 378 * 379 * <p>See <a href="{@docRoot}guide/practices/screens_support.html">Supporting 380 * Multiple Screens</a> for more information.</p> 381 */ 382 public int screenLayout; 383 384 /** 385 * An undefined fontWeightAdjustment. 386 */ 387 public static final int FONT_WEIGHT_ADJUSTMENT_UNDEFINED = Integer.MAX_VALUE; 388 389 /** 390 * Adjustment in text font weight. Used to reflect the current user preference for increasing 391 * font weight. 392 * 393 * <p> If the text font weight is less than the minimum of 1, 1 will be used. If the font weight 394 * exceeds the maximum of 1000, 1000 will be used. 395 * 396 * @see android.graphics.Typeface#create(Typeface, int, boolean) 397 * @see android.graphics.fonts.FontStyle#FONT_WEIGHT_MIN 398 * @see android.graphics.fonts.FontStyle#FONT_WEIGHT_MAX 399 */ 400 public int fontWeightAdjustment; 401 402 /** 403 * Configuration relating to the windowing state of the object associated with this 404 * Configuration. Contents of this field are not intended to affect resources, but need to be 405 * communicated and propagated at the same time as the rest of Configuration. 406 * @hide 407 */ 408 @TestApi 409 public final WindowConfiguration windowConfiguration = new WindowConfiguration(); 410 411 /** @hide */ resetScreenLayout(int curLayout)412 static public int resetScreenLayout(int curLayout) { 413 return (curLayout&~(SCREENLAYOUT_LONG_MASK | SCREENLAYOUT_SIZE_MASK 414 | SCREENLAYOUT_COMPAT_NEEDED)) 415 | (SCREENLAYOUT_LONG_YES | SCREENLAYOUT_SIZE_XLARGE); 416 } 417 418 /** @hide */ reduceScreenLayout(int curLayout, int longSizeDp, int shortSizeDp)419 static public int reduceScreenLayout(int curLayout, int longSizeDp, int shortSizeDp) { 420 int screenLayoutSize; 421 boolean screenLayoutLong; 422 boolean screenLayoutCompatNeeded; 423 424 // These semi-magic numbers define our compatibility modes for 425 // applications with different screens. These are guarantees to 426 // app developers about the space they can expect for a particular 427 // configuration. DO NOT CHANGE! 428 if (longSizeDp < 470) { 429 // This is shorter than an HVGA normal density screen (which 430 // is 480 pixels on its long side). 431 screenLayoutSize = SCREENLAYOUT_SIZE_SMALL; 432 screenLayoutLong = false; 433 screenLayoutCompatNeeded = false; 434 } else { 435 // What size is this screen screen? 436 if (longSizeDp >= 960 && shortSizeDp >= 720) { 437 // 1.5xVGA or larger screens at medium density are the point 438 // at which we consider it to be an extra large screen. 439 screenLayoutSize = SCREENLAYOUT_SIZE_XLARGE; 440 } else if (longSizeDp >= 640 && shortSizeDp >= 480) { 441 // VGA or larger screens at medium density are the point 442 // at which we consider it to be a large screen. 443 screenLayoutSize = SCREENLAYOUT_SIZE_LARGE; 444 } else { 445 screenLayoutSize = SCREENLAYOUT_SIZE_NORMAL; 446 } 447 448 // If this screen is wider than normal HVGA, or taller 449 // than FWVGA, then for old apps we want to run in size 450 // compatibility mode. 451 if (shortSizeDp > 321 || longSizeDp > 570) { 452 screenLayoutCompatNeeded = true; 453 } else { 454 screenLayoutCompatNeeded = false; 455 } 456 457 // Is this a long screen? 458 if (((longSizeDp*3)/5) >= (shortSizeDp-1)) { 459 // Anything wider than WVGA (5:3) is considering to be long. 460 screenLayoutLong = true; 461 } else { 462 screenLayoutLong = false; 463 } 464 } 465 466 // Now reduce the last screenLayout to not be better than what we 467 // have found. 468 if (!screenLayoutLong) { 469 curLayout = (curLayout&~SCREENLAYOUT_LONG_MASK) | SCREENLAYOUT_LONG_NO; 470 } 471 if (screenLayoutCompatNeeded) { 472 curLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED; 473 } 474 int curSize = curLayout&SCREENLAYOUT_SIZE_MASK; 475 if (screenLayoutSize < curSize) { 476 curLayout = (curLayout&~SCREENLAYOUT_SIZE_MASK) | screenLayoutSize; 477 } 478 return curLayout; 479 } 480 481 /** @hide */ configurationDiffToString(int diff)482 public static String configurationDiffToString(int diff) { 483 ArrayList<String> list = new ArrayList<>(); 484 if ((diff & ActivityInfo.CONFIG_MCC) != 0) { 485 list.add("CONFIG_MCC"); 486 } 487 if ((diff & ActivityInfo.CONFIG_MNC) != 0) { 488 list.add("CONFIG_MNC"); 489 } 490 if ((diff & ActivityInfo.CONFIG_LOCALE) != 0) { 491 list.add("CONFIG_LOCALE"); 492 } 493 if ((diff & ActivityInfo.CONFIG_TOUCHSCREEN) != 0) { 494 list.add("CONFIG_TOUCHSCREEN"); 495 } 496 if ((diff & ActivityInfo.CONFIG_KEYBOARD) != 0) { 497 list.add("CONFIG_KEYBOARD"); 498 } 499 if ((diff & ActivityInfo.CONFIG_KEYBOARD_HIDDEN) != 0) { 500 list.add("CONFIG_KEYBOARD_HIDDEN"); 501 } 502 if ((diff & ActivityInfo.CONFIG_NAVIGATION) != 0) { 503 list.add("CONFIG_NAVIGATION"); 504 } 505 if ((diff & ActivityInfo.CONFIG_ORIENTATION) != 0) { 506 list.add("CONFIG_ORIENTATION"); 507 } 508 if ((diff & ActivityInfo.CONFIG_SCREEN_LAYOUT) != 0) { 509 list.add("CONFIG_SCREEN_LAYOUT"); 510 } 511 if ((diff & ActivityInfo.CONFIG_COLOR_MODE) != 0) { 512 list.add("CONFIG_COLOR_MODE"); 513 } 514 if ((diff & ActivityInfo.CONFIG_UI_MODE) != 0) { 515 list.add("CONFIG_UI_MODE"); 516 } 517 if ((diff & ActivityInfo.CONFIG_SCREEN_SIZE) != 0) { 518 list.add("CONFIG_SCREEN_SIZE"); 519 } 520 if ((diff & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0) { 521 list.add("CONFIG_SMALLEST_SCREEN_SIZE"); 522 } 523 if ((diff & ActivityInfo.CONFIG_DENSITY) != 0) { 524 list.add("CONFIG_DENSITY"); 525 } 526 if ((diff & ActivityInfo.CONFIG_LAYOUT_DIRECTION) != 0) { 527 list.add("CONFIG_LAYOUT_DIRECTION"); 528 } 529 if ((diff & ActivityInfo.CONFIG_FONT_SCALE) != 0) { 530 list.add("CONFIG_FONT_SCALE"); 531 } 532 if ((diff & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) { 533 list.add("CONFIG_ASSETS_PATHS"); 534 } 535 if ((diff & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0) { 536 list.add("CONFIG_WINDOW_CONFIGURATION"); 537 } 538 if ((diff & ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT) != 0) { 539 list.add("CONFIG_AUTO_BOLD_TEXT"); 540 } 541 if ((diff & ActivityInfo.CONFIG_GRAMMATICAL_GENDER) != 0) { 542 list.add("CONFIG_GRAMMATICAL_GENDER"); 543 } 544 return "{" + TextUtils.join(", ", list) + "}"; 545 } 546 547 /** 548 * Check if the Configuration's current {@link #screenLayout} is at 549 * least the given size. 550 * 551 * @param size The desired size, either {@link #SCREENLAYOUT_SIZE_SMALL}, 552 * {@link #SCREENLAYOUT_SIZE_NORMAL}, {@link #SCREENLAYOUT_SIZE_LARGE}, or 553 * {@link #SCREENLAYOUT_SIZE_XLARGE}. 554 * @return Returns true if the current screen layout size is at least 555 * the given size. 556 */ isLayoutSizeAtLeast(int size)557 public boolean isLayoutSizeAtLeast(int size) { 558 int cur = screenLayout&SCREENLAYOUT_SIZE_MASK; 559 if (cur == SCREENLAYOUT_SIZE_UNDEFINED) return false; 560 return cur >= size; 561 } 562 563 /** Constant for {@link #touchscreen}: a value indicating that no value has been set. */ 564 public static final int TOUCHSCREEN_UNDEFINED = 0; 565 /** Constant for {@link #touchscreen}, value corresponding to the 566 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#TouchscreenQualifier">notouch</a> 567 * resource qualifier. */ 568 public static final int TOUCHSCREEN_NOTOUCH = 1; 569 /** @deprecated Not currently supported or used. */ 570 @Deprecated public static final int TOUCHSCREEN_STYLUS = 2; 571 /** Constant for {@link #touchscreen}, value corresponding to the 572 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#TouchscreenQualifier">finger</a> 573 * resource qualifier. */ 574 public static final int TOUCHSCREEN_FINGER = 3; 575 576 /** 577 * The kind of touch screen attached to the device. 578 * One of: {@link #TOUCHSCREEN_NOTOUCH}, {@link #TOUCHSCREEN_FINGER}. 579 */ 580 public int touchscreen; 581 582 /** Constant for {@link #keyboard}: a value indicating that no value has been set. */ 583 public static final int KEYBOARD_UNDEFINED = 0; 584 /** Constant for {@link #keyboard}, value corresponding to the 585 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">nokeys</a> 586 * resource qualifier. */ 587 public static final int KEYBOARD_NOKEYS = 1; 588 /** Constant for {@link #keyboard}, value corresponding to the 589 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">qwerty</a> 590 * resource qualifier. */ 591 public static final int KEYBOARD_QWERTY = 2; 592 /** Constant for {@link #keyboard}, value corresponding to the 593 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">12key</a> 594 * resource qualifier. */ 595 public static final int KEYBOARD_12KEY = 3; 596 597 /** 598 * The kind of keyboard attached to the device. 599 * One of: {@link #KEYBOARD_NOKEYS}, {@link #KEYBOARD_QWERTY}, 600 * {@link #KEYBOARD_12KEY}. 601 */ 602 public int keyboard; 603 604 /** Constant for {@link #keyboardHidden}: a value indicating that no value has been set. */ 605 public static final int KEYBOARDHIDDEN_UNDEFINED = 0; 606 /** Constant for {@link #keyboardHidden}, value corresponding to the 607 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keysexposed</a> 608 * resource qualifier. */ 609 public static final int KEYBOARDHIDDEN_NO = 1; 610 /** Constant for {@link #keyboardHidden}, value corresponding to the 611 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keyshidden</a> 612 * resource qualifier. */ 613 public static final int KEYBOARDHIDDEN_YES = 2; 614 /** Constant matching actual resource implementation. {@hide} */ 615 public static final int KEYBOARDHIDDEN_SOFT = 3; 616 617 /** 618 * A flag indicating whether any keyboard is available. Unlike 619 * {@link #hardKeyboardHidden}, this also takes into account a soft 620 * keyboard, so if the hard keyboard is hidden but there is soft 621 * keyboard available, it will be set to NO. Value is one of: 622 * {@link #KEYBOARDHIDDEN_NO}, {@link #KEYBOARDHIDDEN_YES}. 623 */ 624 public int keyboardHidden; 625 626 /** Constant for {@link #hardKeyboardHidden}: a value indicating that no value has been set. */ 627 public static final int HARDKEYBOARDHIDDEN_UNDEFINED = 0; 628 /** Constant for {@link #hardKeyboardHidden}, value corresponding to the 629 * physical keyboard being exposed. */ 630 public static final int HARDKEYBOARDHIDDEN_NO = 1; 631 /** Constant for {@link #hardKeyboardHidden}, value corresponding to the 632 * physical keyboard being hidden. */ 633 public static final int HARDKEYBOARDHIDDEN_YES = 2; 634 635 /** 636 * A flag indicating whether the hard keyboard has been hidden. This will 637 * be set on a device with a mechanism to hide the keyboard from the 638 * user, when that mechanism is closed. One of: 639 * {@link #HARDKEYBOARDHIDDEN_NO}, {@link #HARDKEYBOARDHIDDEN_YES}. 640 */ 641 public int hardKeyboardHidden; 642 643 /** Constant for {@link #navigation}: a value indicating that no value has been set. */ 644 public static final int NAVIGATION_UNDEFINED = 0; 645 /** Constant for {@link #navigation}, value corresponding to the 646 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">nonav</a> 647 * resource qualifier. */ 648 public static final int NAVIGATION_NONAV = 1; 649 /** Constant for {@link #navigation}, value corresponding to the 650 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">dpad</a> 651 * resource qualifier. */ 652 public static final int NAVIGATION_DPAD = 2; 653 /** Constant for {@link #navigation}, value corresponding to the 654 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">trackball</a> 655 * resource qualifier. */ 656 public static final int NAVIGATION_TRACKBALL = 3; 657 /** Constant for {@link #navigation}, value corresponding to the 658 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">wheel</a> 659 * resource qualifier. */ 660 public static final int NAVIGATION_WHEEL = 4; 661 662 /** 663 * The kind of navigation method available on the device. 664 * One of: {@link #NAVIGATION_NONAV}, {@link #NAVIGATION_DPAD}, 665 * {@link #NAVIGATION_TRACKBALL}, {@link #NAVIGATION_WHEEL}. 666 */ 667 public int navigation; 668 669 /** Constant for {@link #navigationHidden}: a value indicating that no value has been set. */ 670 public static final int NAVIGATIONHIDDEN_UNDEFINED = 0; 671 /** Constant for {@link #navigationHidden}, value corresponding to the 672 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavAvailQualifier">navexposed</a> 673 * resource qualifier. */ 674 public static final int NAVIGATIONHIDDEN_NO = 1; 675 /** Constant for {@link #navigationHidden}, value corresponding to the 676 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavAvailQualifier">navhidden</a> 677 * resource qualifier. */ 678 public static final int NAVIGATIONHIDDEN_YES = 2; 679 680 /** 681 * A flag indicating whether any 5-way or DPAD navigation available. 682 * This will be set on a device with a mechanism to hide the navigation 683 * controls from the user, when that mechanism is closed. One of: 684 * {@link #NAVIGATIONHIDDEN_NO}, {@link #NAVIGATIONHIDDEN_YES}. 685 */ 686 public int navigationHidden; 687 688 /** @hide **/ 689 @IntDef(prefix = {"ORIENTATION_"}, value = { 690 ORIENTATION_UNDEFINED, 691 ORIENTATION_PORTRAIT, 692 ORIENTATION_LANDSCAPE, 693 ORIENTATION_SQUARE 694 }) 695 public @interface Orientation { 696 } 697 698 /** Constant for {@link #orientation}: a value indicating that no value has been set. */ 699 public static final int ORIENTATION_UNDEFINED = 0; 700 /** Constant for {@link #orientation}, value corresponding to the 701 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#OrientationQualifier">port</a> 702 * resource qualifier. */ 703 public static final int ORIENTATION_PORTRAIT = 1; 704 /** Constant for {@link #orientation}, value corresponding to the 705 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#OrientationQualifier">land</a> 706 * resource qualifier. */ 707 public static final int ORIENTATION_LANDSCAPE = 2; 708 /** @deprecated Not currently supported or used. */ 709 @Deprecated public static final int ORIENTATION_SQUARE = 3; 710 711 /** 712 * Overall orientation of the screen. May be one of 713 * {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}. 714 */ 715 @Orientation 716 public int orientation; 717 718 /** Constant for {@link #uiMode}: bits that encode the mode type. */ 719 public static final int UI_MODE_TYPE_MASK = 0x0f; 720 /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK} 721 * value indicating that no mode type has been set. */ 722 public static final int UI_MODE_TYPE_UNDEFINED = 0x00; 723 /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK} 724 * value that corresponds to 725 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">no 726 * UI mode</a> resource qualifier specified. */ 727 public static final int UI_MODE_TYPE_NORMAL = 0x01; 728 /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK} 729 * value that corresponds to the 730 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">desk</a> 731 * resource qualifier. */ 732 public static final int UI_MODE_TYPE_DESK = 0x02; 733 /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK} 734 * value that corresponds to the 735 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">car</a> 736 * resource qualifier. */ 737 public static final int UI_MODE_TYPE_CAR = 0x03; 738 /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK} 739 * value that corresponds to the 740 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">television</a> 741 * resource qualifier. */ 742 public static final int UI_MODE_TYPE_TELEVISION = 0x04; 743 /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK} 744 * value that corresponds to the 745 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">appliance</a> 746 * resource qualifier. */ 747 public static final int UI_MODE_TYPE_APPLIANCE = 0x05; 748 /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK} 749 * value that corresponds to the 750 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">watch</a> 751 * resource qualifier. */ 752 public static final int UI_MODE_TYPE_WATCH = 0x06; 753 /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK} 754 * value that corresponds to the 755 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">vrheadset</a> 756 * resource qualifier. */ 757 public static final int UI_MODE_TYPE_VR_HEADSET = 0x07; 758 759 /** Constant for {@link #uiMode}: bits that encode the night mode. */ 760 public static final int UI_MODE_NIGHT_MASK = 0x30; 761 /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK} 762 * value indicating that no mode type has been set. */ 763 public static final int UI_MODE_NIGHT_UNDEFINED = 0x00; 764 /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK} 765 * value that corresponds to the 766 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NightQualifier">notnight</a> 767 * resource qualifier. */ 768 public static final int UI_MODE_NIGHT_NO = 0x10; 769 /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK} 770 * value that corresponds to the 771 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NightQualifier">night</a> 772 * resource qualifier. */ 773 public static final int UI_MODE_NIGHT_YES = 0x20; 774 775 /** 776 * Bit mask of the ui mode. Currently there are two fields: 777 * <p>The {@link #UI_MODE_TYPE_MASK} bits define the overall ui mode of the 778 * device. They may be one of {@link #UI_MODE_TYPE_UNDEFINED}, 779 * {@link #UI_MODE_TYPE_NORMAL}, {@link #UI_MODE_TYPE_DESK}, 780 * {@link #UI_MODE_TYPE_CAR}, {@link #UI_MODE_TYPE_TELEVISION}, 781 * {@link #UI_MODE_TYPE_APPLIANCE}, {@link #UI_MODE_TYPE_WATCH}, 782 * or {@link #UI_MODE_TYPE_VR_HEADSET}. 783 * 784 * <p>The {@link #UI_MODE_NIGHT_MASK} defines whether the screen 785 * is in a special mode. They may be one of {@link #UI_MODE_NIGHT_UNDEFINED}, 786 * {@link #UI_MODE_NIGHT_NO} or {@link #UI_MODE_NIGHT_YES}. 787 */ 788 public int uiMode; 789 790 /** 791 * Default value for {@link #screenWidthDp} indicating that no width 792 * has been specified. 793 */ 794 public static final int SCREEN_WIDTH_DP_UNDEFINED = 0; 795 796 /** 797 * The width of the available screen space in dp units excluding the area 798 * occupied by {@link android.view.WindowInsets window insets}. 799 * 800 * <aside class="note"><b>Note:</b> The width measurement excludes window 801 * insets even when the app is displayed edge to edge using 802 * {@link android.view.Window#setDecorFitsSystemWindows(boolean) 803 * Window#setDecorFitsSystemWindows(boolean)}.</aside> 804 * 805 * <p>Corresponds to the 806 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#AvailableWidthHeightQualifier"> 807 * available width</a> resource qualifier. Defaults to 808 * {@link #SCREEN_WIDTH_DP_UNDEFINED} if no width is specified. 809 * 810 * <p>In multi-window mode, equals the width of the available display area 811 * of the app window, not the available display area of the device screen 812 * (for example, when apps are displayed side by side in split-screen mode 813 * in landscape orientation). 814 * 815 * <p>For embedded activities, equals the width of the individual 816 * activities, not the width of the app window or the device screen. 817 * 818 * <p>In multiple-screen scenarios, the width measurement can span screens. 819 * For example, if the app is spanning both screens of a dual-screen device 820 * (with the screens side by side), {@code screenWidthDp} represents the 821 * width of both screens excluding the area occupied by window insets. When 822 * the app is restricted to a single screen in a multiple-screen 823 * environment, {@code screenWidthDp} is the width of the screen on which 824 * the app is displayed excluding window insets. 825 * 826 * <p>Differs from {@link android.view.WindowMetrics} by not including 827 * window insets in the width measurement and by expressing the measurement 828 * in dp rather than px. Use {@code screenWidthDp} to obtain the width of 829 * the display area available to an app or embedded activity excluding the 830 * area occupied by window insets. Use 831 * {@link android.view.WindowMetrics#getBounds()} to obtain the horizontal 832 * display area available to an app or embedded activity including the area 833 * occupied by window insets. 834 */ 835 public int screenWidthDp; 836 837 /** 838 * Default value for {@link #screenHeightDp} indicating that no width 839 * has been specified. 840 */ 841 public static final int SCREEN_HEIGHT_DP_UNDEFINED = 0; 842 843 /** 844 * The height of the available screen space in dp units excluding the area 845 * occupied by {@link android.view.WindowInsets window insets}, such as the 846 * status bar, navigation bar, and cutouts. 847 * 848 * <aside class="note"><b>Note:</b> The height measurement excludes window 849 * insets even when the app is displayed edge to edge using 850 * {@link android.view.Window#setDecorFitsSystemWindows(boolean) 851 * Window#setDecorFitsSystemWindows(boolean)}.</aside> 852 * 853 * <p>Corresponds to the 854 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#AvailableWidthHeightQualifier"> 855 * available height</a> resource qualifier. Defaults to 856 * {@link #SCREEN_HEIGHT_DP_UNDEFINED} if no height is specified. 857 * 858 * <p>In multi-window mode, equals the height of the available display area 859 * of the app window, not the available display area of the device screen 860 * (for example, when apps are displayed one above another in split-screen 861 * mode in portrait orientation). 862 * 863 * <p>For embedded activities, equals the height of the individual 864 * activities, not the height of the app window or the device screen. 865 * 866 * <p>In multiple-screen scenarios, the height measurement can span screens. 867 * For example, if the app is spanning both screens of a dual-screen device 868 * rotated 90 degrees (one screen above the other), {@code screenHeightDp} 869 * represents the height of both screens excluding the area occupied by 870 * window insets. When the app is restricted to a single screen in a 871 * multiple-screen environment, {@code screenHeightDp} is the height of the 872 * screen on which the app is displayed excluding window insets. 873 * 874 * <p>Differs from {@link android.view.WindowMetrics} by not including 875 * window insets in the height measurement and by expressing the measurement 876 * in dp rather than px. Use {@code screenHeightDp} to obtain the height of 877 * the display area available to an app or embedded activity excluding the 878 * area occupied by window insets. Use 879 * {@link android.view.WindowMetrics#getBounds()} to obtain the vertical 880 * display area available to an app or embedded activity including the area 881 * occupied by window insets. 882 */ 883 public int screenHeightDp; 884 885 /** 886 * Default value for {@link #smallestScreenWidthDp} indicating that no width 887 * has been specified. 888 */ 889 public static final int SMALLEST_SCREEN_WIDTH_DP_UNDEFINED = 0; 890 891 /** 892 * The smallest screen size an application will see in normal operation. 893 * Corresponds to the 894 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#SmallestScreenWidthQualifier"> 895 * smallest width</a> resource qualifier. This is the smallest value of 896 * {@link #screenWidthDp} and {@link #screenHeightDp} in both portrait and 897 * landscape orientations. Defaults to 898 * {@link #SMALLEST_SCREEN_WIDTH_DP_UNDEFINED} if no width is specified. 899 */ 900 public int smallestScreenWidthDp; 901 902 /** 903 * Default value for {@link #densityDpi} indicating that no width 904 * has been specified. 905 */ 906 public static final int DENSITY_DPI_UNDEFINED = 0; 907 908 /** 909 * Value for {@link #densityDpi} for resources that scale to any density (vector drawables). 910 * {@hide} 911 */ 912 public static final int DENSITY_DPI_ANY = 0xfffe; 913 914 /** 915 * Value for {@link #densityDpi} for resources that are not meant to be scaled. 916 * {@hide} 917 */ 918 public static final int DENSITY_DPI_NONE = 0xffff; 919 920 /** 921 * The target screen density being rendered to, 922 * corresponding to 923 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#DensityQualifier">density</a> 924 * resource qualifier. Set to 925 * {@link #DENSITY_DPI_UNDEFINED} if no density is specified. 926 */ 927 public int densityDpi; 928 929 /** @hide Hack to get this information from WM to app running in compat mode. */ 930 public int compatScreenWidthDp; 931 /** @hide Hack to get this information from WM to app running in compat mode. */ 932 public int compatScreenHeightDp; 933 /** @hide Hack to get this information from WM to app running in compat mode. */ 934 public int compatSmallestScreenWidthDp; 935 936 /** 937 * An undefined assetsSeq. This will not override an existing assetsSeq. 938 * @hide 939 */ 940 public static final int ASSETS_SEQ_UNDEFINED = 0; 941 942 /** 943 * Internal counter that allows us to piggyback off the configuration change mechanism to 944 * signal to apps that the the assets for an Application have changed. A difference in these 945 * between two Configurations will yield a diff flag of 946 * {@link ActivityInfo#CONFIG_ASSETS_PATHS}. 947 * @hide 948 */ 949 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 950 @TestApi 951 public int assetsSeq; 952 953 /** 954 * @hide Internal book-keeping. 955 */ 956 @UnsupportedAppUsage 957 public int seq; 958 959 /** @hide */ 960 @IntDef(flag = true, prefix = { "NATIVE_CONFIG_" }, value = { 961 NATIVE_CONFIG_MCC, 962 NATIVE_CONFIG_MNC, 963 NATIVE_CONFIG_LOCALE, 964 NATIVE_CONFIG_TOUCHSCREEN, 965 NATIVE_CONFIG_KEYBOARD, 966 NATIVE_CONFIG_KEYBOARD_HIDDEN, 967 NATIVE_CONFIG_NAVIGATION, 968 NATIVE_CONFIG_ORIENTATION, 969 NATIVE_CONFIG_DENSITY, 970 NATIVE_CONFIG_SCREEN_SIZE, 971 NATIVE_CONFIG_VERSION, 972 NATIVE_CONFIG_SCREEN_LAYOUT, 973 NATIVE_CONFIG_UI_MODE, 974 NATIVE_CONFIG_SMALLEST_SCREEN_SIZE, 975 NATIVE_CONFIG_LAYOUTDIR, 976 NATIVE_CONFIG_COLOR_MODE, 977 NATIVE_CONFIG_GRAMMATICAL_GENDER, 978 }) 979 @Retention(RetentionPolicy.SOURCE) 980 public @interface NativeConfig {} 981 982 /** @hide Native-specific bit mask for MCC config; DO NOT USE UNLESS YOU ARE SURE. */ 983 public static final int NATIVE_CONFIG_MCC = 0x0001; 984 /** @hide Native-specific bit mask for MNC config; DO NOT USE UNLESS YOU ARE SURE. */ 985 public static final int NATIVE_CONFIG_MNC = 0x0002; 986 /** @hide Native-specific bit mask for LOCALE config; DO NOT USE UNLESS YOU ARE SURE. */ 987 public static final int NATIVE_CONFIG_LOCALE = 0x0004; 988 /** @hide Native-specific bit mask for TOUCHSCREEN config; DO NOT USE UNLESS YOU ARE SURE. */ 989 public static final int NATIVE_CONFIG_TOUCHSCREEN = 0x0008; 990 /** @hide Native-specific bit mask for KEYBOARD config; DO NOT USE UNLESS YOU ARE SURE. */ 991 public static final int NATIVE_CONFIG_KEYBOARD = 0x0010; 992 /** @hide Native-specific bit mask for KEYBOARD_HIDDEN config; DO NOT USE UNLESS YOU 993 * ARE SURE. */ 994 public static final int NATIVE_CONFIG_KEYBOARD_HIDDEN = 0x0020; 995 /** @hide Native-specific bit mask for NAVIGATION config; DO NOT USE UNLESS YOU ARE SURE. */ 996 public static final int NATIVE_CONFIG_NAVIGATION = 0x0040; 997 /** @hide Native-specific bit mask for ORIENTATION config; DO NOT USE UNLESS YOU ARE SURE. */ 998 public static final int NATIVE_CONFIG_ORIENTATION = 0x0080; 999 /** @hide Native-specific bit mask for DENSITY config; DO NOT USE UNLESS YOU ARE SURE. */ 1000 public static final int NATIVE_CONFIG_DENSITY = 0x0100; 1001 /** @hide Native-specific bit mask for SCREEN_SIZE config; DO NOT USE UNLESS YOU ARE SURE. */ 1002 public static final int NATIVE_CONFIG_SCREEN_SIZE = 0x0200; 1003 /** @hide Native-specific bit mask for VERSION config; DO NOT USE UNLESS YOU ARE SURE. */ 1004 public static final int NATIVE_CONFIG_VERSION = 0x0400; 1005 /** @hide Native-specific bit mask for SCREEN_LAYOUT config; DO NOT USE UNLESS YOU ARE SURE. */ 1006 public static final int NATIVE_CONFIG_SCREEN_LAYOUT = 0x0800; 1007 /** @hide Native-specific bit mask for UI_MODE config; DO NOT USE UNLESS YOU ARE SURE. */ 1008 public static final int NATIVE_CONFIG_UI_MODE = 0x1000; 1009 /** @hide Native-specific bit mask for SMALLEST_SCREEN_SIZE config; DO NOT USE UNLESS YOU 1010 * ARE SURE. */ 1011 public static final int NATIVE_CONFIG_SMALLEST_SCREEN_SIZE = 0x2000; 1012 /** @hide Native-specific bit mask for LAYOUTDIR config ; DO NOT USE UNLESS YOU ARE SURE.*/ 1013 public static final int NATIVE_CONFIG_LAYOUTDIR = 0x4000; 1014 /** @hide Native-specific bit mask for COLOR_MODE config ; DO NOT USE UNLESS YOU ARE SURE.*/ 1015 public static final int NATIVE_CONFIG_COLOR_MODE = 0x10000; 1016 /** @hide Native-specific bit mask for GRAMMATICAL_GENDER config; DO NOT USE UNLESS YOU 1017 * ARE SURE.*/ 1018 public static final int NATIVE_CONFIG_GRAMMATICAL_GENDER = 0x20000; 1019 1020 /** 1021 * <p>Construct an invalid Configuration. This state is only suitable for constructing a 1022 * Configuration delta that will be applied to some valid Configuration object. In order to 1023 * create a valid standalone Configuration, you must call {@link #setToDefaults}. </p> 1024 * 1025 * <p>Example:</p> 1026 * <pre class="prettyprint"> 1027 * Configuration validConfig = new Configuration(); 1028 * validConfig.setToDefaults(); 1029 * 1030 * Configuration deltaOnlyConfig = new Configuration(); 1031 * deltaOnlyConfig.orientation = Configuration.ORIENTATION_LANDSCAPE; 1032 * 1033 * validConfig.updateFrom(deltaOnlyConfig); 1034 * </pre> 1035 */ Configuration()1036 public Configuration() { 1037 unset(); 1038 } 1039 1040 /** 1041 * Makes a deep copy suitable for modification. 1042 */ Configuration(Configuration o)1043 public Configuration(Configuration o) { 1044 setTo(o); 1045 } 1046 1047 /* This brings mLocaleList in sync with locale in case a user of the older API who doesn't know 1048 * about setLocales() has changed locale directly. */ fixUpLocaleList()1049 private void fixUpLocaleList() { 1050 if ((locale == null && !mLocaleList.isEmpty()) || 1051 (locale != null && !locale.equals(mLocaleList.get(0)))) { 1052 mLocaleList = locale == null ? LocaleList.getEmptyLocaleList() : new LocaleList(locale); 1053 } 1054 } 1055 1056 /** 1057 * Sets the fields in this object to those in the given Configuration. 1058 * 1059 * @param o The Configuration object used to set the values of this Configuration's fields. 1060 */ setTo(Configuration o)1061 public void setTo(Configuration o) { 1062 fontScale = o.fontScale; 1063 mcc = o.mcc; 1064 mnc = o.mnc; 1065 if (o.locale == null) { 1066 locale = null; 1067 } else if (!o.locale.equals(locale)) { 1068 // Only clone a new Locale instance if we need to: the clone() is 1069 // both CPU and GC intensive. 1070 locale = (Locale) o.locale.clone(); 1071 } 1072 o.fixUpLocaleList(); 1073 mLocaleList = o.mLocaleList; 1074 mGrammaticalGender = o.mGrammaticalGender; 1075 userSetLocale = o.userSetLocale; 1076 touchscreen = o.touchscreen; 1077 keyboard = o.keyboard; 1078 keyboardHidden = o.keyboardHidden; 1079 hardKeyboardHidden = o.hardKeyboardHidden; 1080 navigation = o.navigation; 1081 navigationHidden = o.navigationHidden; 1082 orientation = o.orientation; 1083 screenLayout = o.screenLayout; 1084 colorMode = o.colorMode; 1085 uiMode = o.uiMode; 1086 screenWidthDp = o.screenWidthDp; 1087 screenHeightDp = o.screenHeightDp; 1088 smallestScreenWidthDp = o.smallestScreenWidthDp; 1089 densityDpi = o.densityDpi; 1090 compatScreenWidthDp = o.compatScreenWidthDp; 1091 compatScreenHeightDp = o.compatScreenHeightDp; 1092 compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp; 1093 assetsSeq = o.assetsSeq; 1094 seq = o.seq; 1095 windowConfiguration.setTo(o.windowConfiguration); 1096 fontWeightAdjustment = o.fontWeightAdjustment; 1097 } 1098 toString()1099 public String toString() { 1100 StringBuilder sb = new StringBuilder(128); 1101 sb.append("{"); 1102 sb.append(fontScale); 1103 sb.append(" "); 1104 if (mcc != 0) { 1105 sb.append(mcc); 1106 sb.append("mcc"); 1107 } else { 1108 sb.append("?mcc"); 1109 } 1110 if (mnc != MNC_ZERO) { 1111 sb.append(mnc); 1112 sb.append("mnc"); 1113 } else { 1114 sb.append("?mnc"); 1115 } 1116 fixUpLocaleList(); 1117 if (!mLocaleList.isEmpty()) { 1118 sb.append(" "); 1119 sb.append(mLocaleList); 1120 } else { 1121 sb.append(" ?localeList"); 1122 } 1123 if (mGrammaticalGender != 0) { 1124 switch (mGrammaticalGender) { 1125 case GRAMMATICAL_GENDER_NEUTRAL: sb.append(" neuter"); break; 1126 case GRAMMATICAL_GENDER_FEMININE: sb.append(" feminine"); break; 1127 case GRAMMATICAL_GENDER_MASCULINE: sb.append(" masculine"); break; 1128 case GRAMMATICAL_GENDER_NOT_SPECIFIED: sb.append(" ?grgend"); break; 1129 } 1130 } 1131 int layoutDir = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK); 1132 switch (layoutDir) { 1133 case SCREENLAYOUT_LAYOUTDIR_UNDEFINED: sb.append(" ?layoutDir"); break; 1134 case SCREENLAYOUT_LAYOUTDIR_LTR: sb.append(" ldltr"); break; 1135 case SCREENLAYOUT_LAYOUTDIR_RTL: sb.append(" ldrtl"); break; 1136 default: sb.append(" layoutDir="); 1137 sb.append(layoutDir >> SCREENLAYOUT_LAYOUTDIR_SHIFT); break; 1138 } 1139 if (smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { 1140 sb.append(" sw"); sb.append(smallestScreenWidthDp); sb.append("dp"); 1141 } else { 1142 sb.append(" ?swdp"); 1143 } 1144 if (screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) { 1145 sb.append(" w"); sb.append(screenWidthDp); sb.append("dp"); 1146 } else { 1147 sb.append(" ?wdp"); 1148 } 1149 if (screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) { 1150 sb.append(" h"); sb.append(screenHeightDp); sb.append("dp"); 1151 } else { 1152 sb.append(" ?hdp"); 1153 } 1154 if (densityDpi != DENSITY_DPI_UNDEFINED) { 1155 sb.append(" "); sb.append(densityDpi); sb.append("dpi"); 1156 } else { 1157 sb.append(" ?density"); 1158 } 1159 switch ((screenLayout&SCREENLAYOUT_SIZE_MASK)) { 1160 case SCREENLAYOUT_SIZE_UNDEFINED: sb.append(" ?lsize"); break; 1161 case SCREENLAYOUT_SIZE_SMALL: sb.append(" smll"); break; 1162 case SCREENLAYOUT_SIZE_NORMAL: sb.append(" nrml"); break; 1163 case SCREENLAYOUT_SIZE_LARGE: sb.append(" lrg"); break; 1164 case SCREENLAYOUT_SIZE_XLARGE: sb.append(" xlrg"); break; 1165 default: sb.append(" layoutSize="); 1166 sb.append(screenLayout&SCREENLAYOUT_SIZE_MASK); break; 1167 } 1168 switch ((screenLayout&SCREENLAYOUT_LONG_MASK)) { 1169 case SCREENLAYOUT_LONG_UNDEFINED: sb.append(" ?long"); break; 1170 case SCREENLAYOUT_LONG_NO: /* not-long is not interesting to print */ break; 1171 case SCREENLAYOUT_LONG_YES: sb.append(" long"); break; 1172 default: sb.append(" layoutLong="); 1173 sb.append(screenLayout&SCREENLAYOUT_LONG_MASK); break; 1174 } 1175 switch ((colorMode &COLOR_MODE_HDR_MASK)) { 1176 case COLOR_MODE_HDR_UNDEFINED: sb.append(" ?ldr"); break; // most likely not HDR 1177 case COLOR_MODE_HDR_NO: /* ldr is not interesting to print */ break; 1178 case COLOR_MODE_HDR_YES: sb.append(" hdr"); break; 1179 default: sb.append(" dynamicRange="); 1180 sb.append(colorMode &COLOR_MODE_HDR_MASK); break; 1181 } 1182 switch ((colorMode &COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) { 1183 case COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED: sb.append(" ?wideColorGamut"); break; 1184 case COLOR_MODE_WIDE_COLOR_GAMUT_NO: /* not wide is not interesting to print */ break; 1185 case COLOR_MODE_WIDE_COLOR_GAMUT_YES: sb.append(" widecg"); break; 1186 default: sb.append(" wideColorGamut="); 1187 sb.append(colorMode &COLOR_MODE_WIDE_COLOR_GAMUT_MASK); break; 1188 } 1189 switch (orientation) { 1190 case ORIENTATION_UNDEFINED: sb.append(" ?orien"); break; 1191 case ORIENTATION_LANDSCAPE: sb.append(" land"); break; 1192 case ORIENTATION_PORTRAIT: sb.append(" port"); break; 1193 default: sb.append(" orien="); sb.append(orientation); break; 1194 } 1195 switch ((uiMode&UI_MODE_TYPE_MASK)) { 1196 case UI_MODE_TYPE_UNDEFINED: sb.append(" ?uimode"); break; 1197 case UI_MODE_TYPE_NORMAL: /* normal is not interesting to print */ break; 1198 case UI_MODE_TYPE_DESK: sb.append(" desk"); break; 1199 case UI_MODE_TYPE_CAR: sb.append(" car"); break; 1200 case UI_MODE_TYPE_TELEVISION: sb.append(" television"); break; 1201 case UI_MODE_TYPE_APPLIANCE: sb.append(" appliance"); break; 1202 case UI_MODE_TYPE_WATCH: sb.append(" watch"); break; 1203 case UI_MODE_TYPE_VR_HEADSET: sb.append(" vrheadset"); break; 1204 default: sb.append(" uimode="); sb.append(uiMode&UI_MODE_TYPE_MASK); break; 1205 } 1206 switch ((uiMode&UI_MODE_NIGHT_MASK)) { 1207 case UI_MODE_NIGHT_UNDEFINED: sb.append(" ?night"); break; 1208 case UI_MODE_NIGHT_NO: /* not-night is not interesting to print */ break; 1209 case UI_MODE_NIGHT_YES: sb.append(" night"); break; 1210 default: sb.append(" night="); sb.append(uiMode&UI_MODE_NIGHT_MASK); break; 1211 } 1212 switch (touchscreen) { 1213 case TOUCHSCREEN_UNDEFINED: sb.append(" ?touch"); break; 1214 case TOUCHSCREEN_NOTOUCH: sb.append(" -touch"); break; 1215 case TOUCHSCREEN_STYLUS: sb.append(" stylus"); break; 1216 case TOUCHSCREEN_FINGER: sb.append(" finger"); break; 1217 default: sb.append(" touch="); sb.append(touchscreen); break; 1218 } 1219 switch (keyboard) { 1220 case KEYBOARD_UNDEFINED: sb.append(" ?keyb"); break; 1221 case KEYBOARD_NOKEYS: sb.append(" -keyb"); break; 1222 case KEYBOARD_QWERTY: sb.append(" qwerty"); break; 1223 case KEYBOARD_12KEY: sb.append(" 12key"); break; 1224 default: sb.append(" keys="); sb.append(keyboard); break; 1225 } 1226 switch (keyboardHidden) { 1227 case KEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break; 1228 case KEYBOARDHIDDEN_NO: sb.append("/v"); break; 1229 case KEYBOARDHIDDEN_YES: sb.append("/h"); break; 1230 case KEYBOARDHIDDEN_SOFT: sb.append("/s"); break; 1231 default: sb.append("/"); sb.append(keyboardHidden); break; 1232 } 1233 switch (hardKeyboardHidden) { 1234 case HARDKEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break; 1235 case HARDKEYBOARDHIDDEN_NO: sb.append("/v"); break; 1236 case HARDKEYBOARDHIDDEN_YES: sb.append("/h"); break; 1237 default: sb.append("/"); sb.append(hardKeyboardHidden); break; 1238 } 1239 switch (navigation) { 1240 case NAVIGATION_UNDEFINED: sb.append(" ?nav"); break; 1241 case NAVIGATION_NONAV: sb.append(" -nav"); break; 1242 case NAVIGATION_DPAD: sb.append(" dpad"); break; 1243 case NAVIGATION_TRACKBALL: sb.append(" tball"); break; 1244 case NAVIGATION_WHEEL: sb.append(" wheel"); break; 1245 default: sb.append(" nav="); sb.append(navigation); break; 1246 } 1247 switch (navigationHidden) { 1248 case NAVIGATIONHIDDEN_UNDEFINED: sb.append("/?"); break; 1249 case NAVIGATIONHIDDEN_NO: sb.append("/v"); break; 1250 case NAVIGATIONHIDDEN_YES: sb.append("/h"); break; 1251 default: sb.append("/"); sb.append(navigationHidden); break; 1252 } 1253 sb.append(" winConfig="); sb.append(windowConfiguration); 1254 if (assetsSeq != 0) { 1255 sb.append(" as.").append(assetsSeq); 1256 } 1257 if (seq != 0) { 1258 sb.append(" s.").append(seq); 1259 } 1260 if (fontWeightAdjustment != FONT_WEIGHT_ADJUSTMENT_UNDEFINED) { 1261 sb.append(" fontWeightAdjustment="); 1262 sb.append(fontWeightAdjustment); 1263 } else { 1264 sb.append(" ?fontWeightAdjustment"); 1265 } 1266 sb.append('}'); 1267 return sb.toString(); 1268 } 1269 1270 /** 1271 * Write to a protocol buffer output stream. 1272 * Protocol buffer message definition at {@link android.content.ConfigurationProto} 1273 * Has the option to ignore fields that don't need to be persisted to disk. 1274 * 1275 * @param protoOutputStream Stream to write the Configuration object to. 1276 * @param fieldId Field Id of the Configuration as defined in the parent message 1277 * @param persisted Note if this proto will be persisted to disk 1278 * @param critical If true, reduce amount of data written. 1279 * @hide 1280 */ dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean persisted, boolean critical)1281 public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean persisted, 1282 boolean critical) { 1283 final long token = protoOutputStream.start(fieldId); 1284 if (!critical) { 1285 protoOutputStream.write(FONT_SCALE, fontScale); 1286 protoOutputStream.write(MCC, mcc); 1287 protoOutputStream.write(MNC, mnc); 1288 if (mLocaleList != null) { 1289 protoOutputStream.write(LOCALE_LIST, mLocaleList.toLanguageTags()); 1290 } 1291 protoOutputStream.write(SCREEN_LAYOUT, screenLayout); 1292 protoOutputStream.write(COLOR_MODE, colorMode); 1293 protoOutputStream.write(TOUCHSCREEN, touchscreen); 1294 protoOutputStream.write(KEYBOARD, keyboard); 1295 protoOutputStream.write(KEYBOARD_HIDDEN, keyboardHidden); 1296 protoOutputStream.write(HARD_KEYBOARD_HIDDEN, hardKeyboardHidden); 1297 protoOutputStream.write(NAVIGATION, navigation); 1298 protoOutputStream.write(NAVIGATION_HIDDEN, navigationHidden); 1299 protoOutputStream.write(UI_MODE, uiMode); 1300 protoOutputStream.write(SMALLEST_SCREEN_WIDTH_DP, smallestScreenWidthDp); 1301 protoOutputStream.write(DENSITY_DPI, densityDpi); 1302 // For persistence, we do not care about window configuration 1303 if (!persisted && windowConfiguration != null) { 1304 windowConfiguration.dumpDebug(protoOutputStream, WINDOW_CONFIGURATION); 1305 } 1306 protoOutputStream.write(FONT_WEIGHT_ADJUSTMENT, fontWeightAdjustment); 1307 } 1308 protoOutputStream.write(ORIENTATION, orientation); 1309 protoOutputStream.write(SCREEN_WIDTH_DP, screenWidthDp); 1310 protoOutputStream.write(SCREEN_HEIGHT_DP, screenHeightDp); 1311 protoOutputStream.write(GRAMMATICAL_GENDER, mGrammaticalGender); 1312 protoOutputStream.end(token); 1313 } 1314 1315 /** 1316 * Write to a protocol buffer output stream. 1317 * Protocol buffer message definition at {@link android.content.ConfigurationProto} 1318 * 1319 * @param protoOutputStream Stream to write the Configuration object to. 1320 * @param fieldId Field Id of the Configuration as defined in the parent message 1321 * @hide 1322 */ dumpDebug(ProtoOutputStream protoOutputStream, long fieldId)1323 public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId) { 1324 dumpDebug(protoOutputStream, fieldId, false /* persisted */, false /* critical */); 1325 } 1326 1327 /** 1328 * Write to a protocol buffer output stream. 1329 * Protocol buffer message definition at {@link android.content.ConfigurationProto} 1330 * 1331 * @param protoOutputStream Stream to write the Configuration object to. 1332 * @param fieldId Field Id of the Configuration as defined in the parent message 1333 * @param critical If true, reduce amount of data written. 1334 * @hide 1335 */ dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean critical)1336 public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean critical) { 1337 dumpDebug(protoOutputStream, fieldId, false /* persisted */, critical); 1338 } 1339 1340 /** 1341 * Read from a protocol buffer output stream. 1342 * Protocol buffer message definition at {@link android.content.ConfigurationProto} 1343 * 1344 * @param protoInputStream Stream to read the Configuration object from. 1345 * @param fieldId Field Id of the Configuration as defined in the parent message 1346 * @hide 1347 */ readFromProto(ProtoInputStream protoInputStream, long fieldId)1348 public void readFromProto(ProtoInputStream protoInputStream, long fieldId) throws IOException { 1349 final long token = protoInputStream.start(fieldId); 1350 final List<Locale> list = new ArrayList(); 1351 try { 1352 while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { 1353 switch (protoInputStream.getFieldNumber()) { 1354 case (int) FONT_SCALE: 1355 fontScale = protoInputStream.readFloat(FONT_SCALE); 1356 break; 1357 case (int) MCC: 1358 mcc = protoInputStream.readInt(MCC); 1359 break; 1360 case (int) MNC: 1361 mnc = protoInputStream.readInt(MNC); 1362 break; 1363 case (int) LOCALES: 1364 // Parse the Locale here to handle all the repeated Locales 1365 // The LocaleList will be created when the message is completed 1366 final long localeToken = protoInputStream.start(LOCALES); 1367 String language = ""; 1368 String country = ""; 1369 String variant = ""; 1370 String script = ""; 1371 try { 1372 while (protoInputStream.nextField() 1373 != ProtoInputStream.NO_MORE_FIELDS) { 1374 switch (protoInputStream.getFieldNumber()) { 1375 case (int) LocaleProto.LANGUAGE: 1376 language = protoInputStream.readString( 1377 LocaleProto.LANGUAGE); 1378 break; 1379 case (int) LocaleProto.COUNTRY: 1380 country = protoInputStream.readString(LocaleProto.COUNTRY); 1381 break; 1382 case (int) LocaleProto.VARIANT: 1383 variant = protoInputStream.readString(LocaleProto.VARIANT); 1384 break; 1385 case (int) LocaleProto.SCRIPT: 1386 script = protoInputStream.readString(LocaleProto.SCRIPT); 1387 break; 1388 } 1389 } 1390 } catch (WireTypeMismatchException wtme) { 1391 // rethrow for caller deal with 1392 throw wtme; 1393 } finally { 1394 protoInputStream.end(localeToken); 1395 try { 1396 final Locale locale = new Locale.Builder() 1397 .setLanguage(language) 1398 .setRegion(country) 1399 .setVariant(variant) 1400 .setScript(script) 1401 .build(); 1402 // Log a WTF here if a repeated locale is found to avoid throwing an 1403 // exception in system server when LocaleList is created below 1404 final int inListIndex = list.indexOf(locale); 1405 if (inListIndex != -1) { 1406 Slog.wtf(TAG, "Repeated locale (" + list.get(inListIndex) + ")" 1407 + " found when trying to add: " + locale.toString()); 1408 } else { 1409 list.add(locale); 1410 } 1411 } catch (IllformedLocaleException e) { 1412 Slog.e(TAG, "readFromProto error building locale with: " 1413 + "language-" + language + ";country-" + country 1414 + ";variant-" + variant + ";script-" + script); 1415 } 1416 } 1417 break; 1418 case (int) SCREEN_LAYOUT: 1419 screenLayout = protoInputStream.readInt(SCREEN_LAYOUT); 1420 break; 1421 case (int) COLOR_MODE: 1422 colorMode = protoInputStream.readInt(COLOR_MODE); 1423 break; 1424 case (int) TOUCHSCREEN: 1425 touchscreen = protoInputStream.readInt(TOUCHSCREEN); 1426 break; 1427 case (int) KEYBOARD: 1428 keyboard = protoInputStream.readInt(KEYBOARD); 1429 break; 1430 case (int) KEYBOARD_HIDDEN: 1431 keyboardHidden = protoInputStream.readInt(KEYBOARD_HIDDEN); 1432 break; 1433 case (int) HARD_KEYBOARD_HIDDEN: 1434 hardKeyboardHidden = protoInputStream.readInt(HARD_KEYBOARD_HIDDEN); 1435 break; 1436 case (int) NAVIGATION: 1437 navigation = protoInputStream.readInt(NAVIGATION); 1438 break; 1439 case (int) NAVIGATION_HIDDEN: 1440 navigationHidden = protoInputStream.readInt(NAVIGATION_HIDDEN); 1441 break; 1442 case (int) ORIENTATION: 1443 orientation = protoInputStream.readInt(ORIENTATION); 1444 break; 1445 case (int) UI_MODE: 1446 uiMode = protoInputStream.readInt(UI_MODE); 1447 break; 1448 case (int) SCREEN_WIDTH_DP: 1449 screenWidthDp = protoInputStream.readInt(SCREEN_WIDTH_DP); 1450 break; 1451 case (int) SCREEN_HEIGHT_DP: 1452 screenHeightDp = protoInputStream.readInt(SCREEN_HEIGHT_DP); 1453 break; 1454 case (int) SMALLEST_SCREEN_WIDTH_DP: 1455 smallestScreenWidthDp = protoInputStream.readInt(SMALLEST_SCREEN_WIDTH_DP); 1456 break; 1457 case (int) DENSITY_DPI: 1458 densityDpi = protoInputStream.readInt(DENSITY_DPI); 1459 break; 1460 case (int) WINDOW_CONFIGURATION: 1461 windowConfiguration.readFromProto(protoInputStream, WINDOW_CONFIGURATION); 1462 break; 1463 case (int) LOCALE_LIST: 1464 try { 1465 setLocales(LocaleList.forLanguageTags(protoInputStream.readString( 1466 LOCALE_LIST))); 1467 } catch (Exception e) { 1468 Slog.e(TAG, "error parsing locale list in configuration.", e); 1469 } 1470 break; 1471 case (int) FONT_WEIGHT_ADJUSTMENT: 1472 fontWeightAdjustment = protoInputStream.readInt(FONT_WEIGHT_ADJUSTMENT); 1473 break; 1474 case (int) GRAMMATICAL_GENDER: 1475 mGrammaticalGender = protoInputStream.readInt(GRAMMATICAL_GENDER); 1476 break; 1477 } 1478 } 1479 } finally { 1480 // Let caller handle any exceptions 1481 if (list.size() > 0) { 1482 //Create the LocaleList from the collected Locales 1483 setLocales(new LocaleList(list.toArray(new Locale[list.size()]))); 1484 } 1485 protoInputStream.end(token); 1486 } 1487 } 1488 1489 /** 1490 * Write full {@link android.content.ResourcesConfigurationProto} to protocol buffer output 1491 * stream. 1492 * 1493 * @param protoOutputStream Stream to write the Configuration object to. 1494 * @param fieldId Field Id of the Configuration as defined in the parent message 1495 * @param metrics Current display information 1496 * @hide 1497 */ writeResConfigToProto(ProtoOutputStream protoOutputStream, long fieldId, DisplayMetrics metrics)1498 public void writeResConfigToProto(ProtoOutputStream protoOutputStream, long fieldId, 1499 DisplayMetrics metrics) { 1500 final int width, height; 1501 if (metrics.widthPixels >= metrics.heightPixels) { 1502 width = metrics.widthPixels; 1503 height = metrics.heightPixels; 1504 } else { 1505 //noinspection SuspiciousNameCombination 1506 width = metrics.heightPixels; 1507 //noinspection SuspiciousNameCombination 1508 height = metrics.widthPixels; 1509 } 1510 1511 final long token = protoOutputStream.start(fieldId); 1512 dumpDebug(protoOutputStream, CONFIGURATION); 1513 protoOutputStream.write(SDK_VERSION, Build.VERSION.RESOURCES_SDK_INT); 1514 protoOutputStream.write(SCREEN_WIDTH_PX, width); 1515 protoOutputStream.write(SCREEN_HEIGHT_PX, height); 1516 protoOutputStream.end(token); 1517 } 1518 1519 /** 1520 * Convert the UI mode to a human readable format. 1521 * @hide 1522 */ uiModeToString(int uiMode)1523 public static String uiModeToString(int uiMode) { 1524 switch (uiMode) { 1525 case UI_MODE_TYPE_UNDEFINED: 1526 return "UI_MODE_TYPE_UNDEFINED"; 1527 case UI_MODE_TYPE_NORMAL: 1528 return "UI_MODE_TYPE_NORMAL"; 1529 case UI_MODE_TYPE_DESK: 1530 return "UI_MODE_TYPE_DESK"; 1531 case UI_MODE_TYPE_CAR: 1532 return "UI_MODE_TYPE_CAR"; 1533 case UI_MODE_TYPE_TELEVISION: 1534 return "UI_MODE_TYPE_TELEVISION"; 1535 case UI_MODE_TYPE_APPLIANCE: 1536 return "UI_MODE_TYPE_APPLIANCE"; 1537 case UI_MODE_TYPE_WATCH: 1538 return "UI_MODE_TYPE_WATCH"; 1539 case UI_MODE_TYPE_VR_HEADSET: 1540 return "UI_MODE_TYPE_VR_HEADSET"; 1541 default: 1542 return Integer.toString(uiMode); 1543 } 1544 } 1545 1546 /** 1547 * Set this object to the system defaults. 1548 */ setToDefaults()1549 public void setToDefaults() { 1550 fontScale = 1; 1551 mcc = mnc = 0; 1552 mLocaleList = LocaleList.getEmptyLocaleList(); 1553 locale = null; 1554 userSetLocale = false; 1555 touchscreen = TOUCHSCREEN_UNDEFINED; 1556 keyboard = KEYBOARD_UNDEFINED; 1557 keyboardHidden = KEYBOARDHIDDEN_UNDEFINED; 1558 hardKeyboardHidden = HARDKEYBOARDHIDDEN_UNDEFINED; 1559 navigation = NAVIGATION_UNDEFINED; 1560 navigationHidden = NAVIGATIONHIDDEN_UNDEFINED; 1561 orientation = ORIENTATION_UNDEFINED; 1562 screenLayout = SCREENLAYOUT_UNDEFINED; 1563 colorMode = COLOR_MODE_UNDEFINED; 1564 uiMode = UI_MODE_TYPE_UNDEFINED; 1565 screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED; 1566 screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED; 1567 smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; 1568 densityDpi = DENSITY_DPI_UNDEFINED; 1569 assetsSeq = ASSETS_SEQ_UNDEFINED; 1570 seq = 0; 1571 windowConfiguration.setToDefaults(); 1572 fontWeightAdjustment = FONT_WEIGHT_ADJUSTMENT_UNDEFINED; 1573 mGrammaticalGender = GRAMMATICAL_GENDER_NOT_SPECIFIED; 1574 } 1575 1576 /** 1577 * Set this object to completely undefined. 1578 * @hide 1579 */ unset()1580 public void unset() { 1581 setToDefaults(); 1582 fontScale = 0; 1583 } 1584 1585 /** {@hide} */ 1586 @UnsupportedAppUsage makeDefault()1587 @Deprecated public void makeDefault() { 1588 setToDefaults(); 1589 } 1590 1591 /** 1592 * Copies the fields from delta into this Configuration object, keeping 1593 * track of which ones have changed. Any undefined fields in {@code delta} 1594 * are ignored and not copied in to the current Configuration. 1595 * 1596 * @return a bit mask of the changed fields, as per {@link #diff} 1597 */ updateFrom(@onNull Configuration delta)1598 public @Config int updateFrom(@NonNull Configuration delta) { 1599 int changed = 0; 1600 if (delta.fontScale > 0 && fontScale != delta.fontScale) { 1601 changed |= ActivityInfo.CONFIG_FONT_SCALE; 1602 fontScale = delta.fontScale; 1603 } 1604 if (delta.mcc != 0 && mcc != delta.mcc) { 1605 changed |= ActivityInfo.CONFIG_MCC; 1606 mcc = delta.mcc; 1607 } 1608 if (delta.mnc != 0 && mnc != delta.mnc) { 1609 changed |= ActivityInfo.CONFIG_MNC; 1610 mnc = delta.mnc; 1611 } 1612 fixUpLocaleList(); 1613 delta.fixUpLocaleList(); 1614 if (!delta.mLocaleList.isEmpty() && !mLocaleList.equals(delta.mLocaleList)) { 1615 changed |= ActivityInfo.CONFIG_LOCALE; 1616 mLocaleList = delta.mLocaleList; 1617 // delta.locale can't be null, since delta.mLocaleList is not empty. 1618 if (!delta.locale.equals(locale)) { 1619 locale = (Locale) delta.locale.clone(); 1620 // If locale has changed, then layout direction is also changed ... 1621 changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; 1622 // ... and we need to update the layout direction (represented by the first 1623 // 2 most significant bits in screenLayout). 1624 setLayoutDirection(locale); 1625 } 1626 } 1627 final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK; 1628 if (deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED && 1629 deltaScreenLayoutDir != (screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) { 1630 screenLayout = (screenLayout & ~SCREENLAYOUT_LAYOUTDIR_MASK) | deltaScreenLayoutDir; 1631 changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; 1632 } 1633 if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0))) 1634 { 1635 changed |= ActivityInfo.CONFIG_LOCALE; 1636 userSetLocale = true; 1637 } 1638 if (delta.touchscreen != TOUCHSCREEN_UNDEFINED 1639 && touchscreen != delta.touchscreen) { 1640 changed |= ActivityInfo.CONFIG_TOUCHSCREEN; 1641 touchscreen = delta.touchscreen; 1642 } 1643 if (delta.keyboard != KEYBOARD_UNDEFINED 1644 && keyboard != delta.keyboard) { 1645 changed |= ActivityInfo.CONFIG_KEYBOARD; 1646 keyboard = delta.keyboard; 1647 } 1648 if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED 1649 && keyboardHidden != delta.keyboardHidden) { 1650 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 1651 keyboardHidden = delta.keyboardHidden; 1652 } 1653 if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED 1654 && hardKeyboardHidden != delta.hardKeyboardHidden) { 1655 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 1656 hardKeyboardHidden = delta.hardKeyboardHidden; 1657 } 1658 if (delta.navigation != NAVIGATION_UNDEFINED 1659 && navigation != delta.navigation) { 1660 changed |= ActivityInfo.CONFIG_NAVIGATION; 1661 navigation = delta.navigation; 1662 } 1663 if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED 1664 && navigationHidden != delta.navigationHidden) { 1665 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 1666 navigationHidden = delta.navigationHidden; 1667 } 1668 if (delta.orientation != ORIENTATION_UNDEFINED 1669 && orientation != delta.orientation) { 1670 changed |= ActivityInfo.CONFIG_ORIENTATION; 1671 orientation = delta.orientation; 1672 } 1673 if (((delta.screenLayout & SCREENLAYOUT_SIZE_MASK) != SCREENLAYOUT_SIZE_UNDEFINED) 1674 && (delta.screenLayout & SCREENLAYOUT_SIZE_MASK) 1675 != (screenLayout & SCREENLAYOUT_SIZE_MASK)) { 1676 changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; 1677 screenLayout = (screenLayout & ~SCREENLAYOUT_SIZE_MASK) 1678 | (delta.screenLayout & SCREENLAYOUT_SIZE_MASK); 1679 } 1680 if (((delta.screenLayout & SCREENLAYOUT_LONG_MASK) != SCREENLAYOUT_LONG_UNDEFINED) 1681 && (delta.screenLayout & SCREENLAYOUT_LONG_MASK) 1682 != (screenLayout & SCREENLAYOUT_LONG_MASK)) { 1683 changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; 1684 screenLayout = (screenLayout & ~SCREENLAYOUT_LONG_MASK) 1685 | (delta.screenLayout & SCREENLAYOUT_LONG_MASK); 1686 } 1687 if (((delta.screenLayout & SCREENLAYOUT_ROUND_MASK) != SCREENLAYOUT_ROUND_UNDEFINED) 1688 && (delta.screenLayout & SCREENLAYOUT_ROUND_MASK) 1689 != (screenLayout & SCREENLAYOUT_ROUND_MASK)) { 1690 changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; 1691 screenLayout = (screenLayout & ~SCREENLAYOUT_ROUND_MASK) 1692 | (delta.screenLayout & SCREENLAYOUT_ROUND_MASK); 1693 } 1694 if ((delta.screenLayout & SCREENLAYOUT_COMPAT_NEEDED) 1695 != (screenLayout & SCREENLAYOUT_COMPAT_NEEDED) 1696 && delta.screenLayout != 0) { 1697 changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; 1698 screenLayout = (screenLayout & ~SCREENLAYOUT_COMPAT_NEEDED) 1699 | (delta.screenLayout & SCREENLAYOUT_COMPAT_NEEDED); 1700 } 1701 1702 if (((delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) != 1703 COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED) 1704 && (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) 1705 != (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) { 1706 changed |= ActivityInfo.CONFIG_COLOR_MODE; 1707 colorMode = (colorMode & ~COLOR_MODE_WIDE_COLOR_GAMUT_MASK) 1708 | (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK); 1709 } 1710 1711 if (((delta.colorMode & COLOR_MODE_HDR_MASK) != COLOR_MODE_HDR_UNDEFINED) 1712 && (delta.colorMode & COLOR_MODE_HDR_MASK) 1713 != (colorMode & COLOR_MODE_HDR_MASK)) { 1714 changed |= ActivityInfo.CONFIG_COLOR_MODE; 1715 colorMode = (colorMode & ~COLOR_MODE_HDR_MASK) 1716 | (delta.colorMode & COLOR_MODE_HDR_MASK); 1717 } 1718 1719 if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED) 1720 && uiMode != delta.uiMode) { 1721 changed |= ActivityInfo.CONFIG_UI_MODE; 1722 if ((delta.uiMode&UI_MODE_TYPE_MASK) != UI_MODE_TYPE_UNDEFINED) { 1723 uiMode = (uiMode&~UI_MODE_TYPE_MASK) 1724 | (delta.uiMode&UI_MODE_TYPE_MASK); 1725 } 1726 if ((delta.uiMode&UI_MODE_NIGHT_MASK) != UI_MODE_NIGHT_UNDEFINED) { 1727 uiMode = (uiMode&~UI_MODE_NIGHT_MASK) 1728 | (delta.uiMode&UI_MODE_NIGHT_MASK); 1729 } 1730 } 1731 if (delta.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED 1732 && screenWidthDp != delta.screenWidthDp) { 1733 changed |= ActivityInfo.CONFIG_SCREEN_SIZE; 1734 screenWidthDp = delta.screenWidthDp; 1735 } 1736 if (delta.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED 1737 && screenHeightDp != delta.screenHeightDp) { 1738 changed |= ActivityInfo.CONFIG_SCREEN_SIZE; 1739 screenHeightDp = delta.screenHeightDp; 1740 } 1741 if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED 1742 && smallestScreenWidthDp != delta.smallestScreenWidthDp) { 1743 changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; 1744 smallestScreenWidthDp = delta.smallestScreenWidthDp; 1745 } 1746 if (delta.densityDpi != DENSITY_DPI_UNDEFINED && 1747 densityDpi != delta.densityDpi) { 1748 changed |= ActivityInfo.CONFIG_DENSITY; 1749 densityDpi = delta.densityDpi; 1750 } 1751 if (delta.compatScreenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) { 1752 compatScreenWidthDp = delta.compatScreenWidthDp; 1753 } 1754 if (delta.compatScreenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) { 1755 compatScreenHeightDp = delta.compatScreenHeightDp; 1756 } 1757 if (delta.compatSmallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { 1758 compatSmallestScreenWidthDp = delta.compatSmallestScreenWidthDp; 1759 } 1760 if (delta.assetsSeq != ASSETS_SEQ_UNDEFINED && delta.assetsSeq != assetsSeq) { 1761 changed |= ActivityInfo.CONFIG_ASSETS_PATHS; 1762 assetsSeq = delta.assetsSeq; 1763 } 1764 if (delta.seq != 0) { 1765 seq = delta.seq; 1766 } 1767 if (windowConfiguration.updateFrom(delta.windowConfiguration) != 0) { 1768 changed |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION; 1769 } 1770 1771 if (delta.fontWeightAdjustment != FONT_WEIGHT_ADJUSTMENT_UNDEFINED 1772 && delta.fontWeightAdjustment != fontWeightAdjustment) { 1773 changed |= ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT; 1774 fontWeightAdjustment = delta.fontWeightAdjustment; 1775 } 1776 if (delta.mGrammaticalGender != mGrammaticalGender) { 1777 changed |= ActivityInfo.CONFIG_GRAMMATICAL_GENDER; 1778 mGrammaticalGender = delta.mGrammaticalGender; 1779 } 1780 1781 return changed; 1782 } 1783 1784 /** 1785 * Copies the fields specified by mask from delta into this Configuration object. This will 1786 * copy anything allowed by the mask (including undefined values). 1787 * @hide 1788 */ setTo(@onNull Configuration delta, @Config int mask, @WindowConfiguration.WindowConfig int windowMask)1789 public void setTo(@NonNull Configuration delta, @Config int mask, 1790 @WindowConfiguration.WindowConfig int windowMask) { 1791 if ((mask & ActivityInfo.CONFIG_FONT_SCALE) != 0) { 1792 fontScale = delta.fontScale; 1793 } 1794 if ((mask & ActivityInfo.CONFIG_MCC) != 0) { 1795 mcc = delta.mcc; 1796 } 1797 if ((mask & ActivityInfo.CONFIG_MNC) != 0) { 1798 mnc = delta.mnc; 1799 } 1800 if ((mask & ActivityInfo.CONFIG_LOCALE) != 0) { 1801 mLocaleList = delta.mLocaleList; 1802 if (!mLocaleList.isEmpty()) { 1803 if (!delta.locale.equals(locale)) { 1804 // Don't churn a new Locale clone unless we're actually changing it 1805 locale = (Locale) delta.locale.clone(); 1806 } 1807 } 1808 } 1809 if ((mask & ActivityInfo.CONFIG_LAYOUT_DIRECTION) != 0) { 1810 final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK; 1811 screenLayout = (screenLayout & ~SCREENLAYOUT_LAYOUTDIR_MASK) | deltaScreenLayoutDir; 1812 } 1813 if ((mask & ActivityInfo.CONFIG_LOCALE) != 0) { 1814 userSetLocale = delta.userSetLocale; 1815 } 1816 if ((mask & ActivityInfo.CONFIG_TOUCHSCREEN) != 0) { 1817 touchscreen = delta.touchscreen; 1818 } 1819 if ((mask & ActivityInfo.CONFIG_KEYBOARD) != 0) { 1820 keyboard = delta.keyboard; 1821 } 1822 if ((mask & ActivityInfo.CONFIG_KEYBOARD_HIDDEN) != 0) { 1823 keyboardHidden = delta.keyboardHidden; 1824 hardKeyboardHidden = delta.hardKeyboardHidden; 1825 navigationHidden = delta.navigationHidden; 1826 } 1827 if ((mask & ActivityInfo.CONFIG_NAVIGATION) != 0) { 1828 navigation = delta.navigation; 1829 } 1830 if ((mask & ActivityInfo.CONFIG_ORIENTATION) != 0) { 1831 orientation = delta.orientation; 1832 } 1833 if ((mask & ActivityInfo.CONFIG_SCREEN_LAYOUT) != 0) { 1834 // Not enough granularity for each component unfortunately. 1835 screenLayout = screenLayout | (delta.screenLayout & ~SCREENLAYOUT_LAYOUTDIR_MASK); 1836 } 1837 if ((mask & ActivityInfo.CONFIG_COLOR_MODE) != 0) { 1838 colorMode = delta.colorMode; 1839 } 1840 if ((mask & ActivityInfo.CONFIG_UI_MODE) != 0) { 1841 uiMode = delta.uiMode; 1842 } 1843 if ((mask & ActivityInfo.CONFIG_SCREEN_SIZE) != 0) { 1844 screenWidthDp = delta.screenWidthDp; 1845 screenHeightDp = delta.screenHeightDp; 1846 } 1847 if ((mask & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0) { 1848 smallestScreenWidthDp = delta.smallestScreenWidthDp; 1849 } 1850 if ((mask & ActivityInfo.CONFIG_DENSITY) != 0) { 1851 densityDpi = delta.densityDpi; 1852 } 1853 if ((mask & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) { 1854 assetsSeq = delta.assetsSeq; 1855 } 1856 if ((mask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0) { 1857 windowConfiguration.setTo(delta.windowConfiguration, windowMask); 1858 } 1859 if ((mask & ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT) != 0) { 1860 fontWeightAdjustment = delta.fontWeightAdjustment; 1861 } 1862 if ((mask & ActivityInfo.CONFIG_GRAMMATICAL_GENDER) != 0) { 1863 mGrammaticalGender = delta.mGrammaticalGender; 1864 } 1865 } 1866 1867 /** 1868 * Return a bit mask of the differences between this Configuration 1869 * object and the given one. Does not change the values of either. Any 1870 * undefined fields in <var>delta</var> are ignored. 1871 * @return Returns a bit mask indicating which configuration 1872 * values have changed. 1873 */ diff(Configuration delta)1874 public @Config int diff(Configuration delta) { 1875 return diff(delta, false /* compareUndefined */, false /* publicOnly */); 1876 } 1877 1878 /** 1879 * Returns the diff against the provided {@link Configuration} excluding values that would 1880 * publicly be equivalent, such as appBounds. 1881 * @param delta {@link Configuration} to compare to. 1882 * 1883 * TODO(b/36812336): Remove once appBounds has been moved out of Configuration. 1884 * {@hide} 1885 */ diffPublicOnly(Configuration delta)1886 public int diffPublicOnly(Configuration delta) { 1887 return diff(delta, false /* compareUndefined */, true /* publicOnly */); 1888 } 1889 1890 /** 1891 * Variation of {@link #diff(Configuration)} with an option to skip checks for undefined values. 1892 * 1893 * @hide 1894 */ diff(Configuration delta, boolean compareUndefined, boolean publicOnly)1895 public int diff(Configuration delta, boolean compareUndefined, boolean publicOnly) { 1896 int changed = 0; 1897 if ((compareUndefined || delta.fontScale > 0) && fontScale != delta.fontScale) { 1898 changed |= ActivityInfo.CONFIG_FONT_SCALE; 1899 } 1900 if ((compareUndefined || delta.mcc != 0) && mcc != delta.mcc) { 1901 changed |= ActivityInfo.CONFIG_MCC; 1902 } 1903 if ((compareUndefined || delta.mnc != 0) && mnc != delta.mnc) { 1904 changed |= ActivityInfo.CONFIG_MNC; 1905 } 1906 fixUpLocaleList(); 1907 delta.fixUpLocaleList(); 1908 if ((compareUndefined || !delta.mLocaleList.isEmpty()) 1909 && !mLocaleList.equals(delta.mLocaleList)) { 1910 changed |= ActivityInfo.CONFIG_LOCALE; 1911 changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; 1912 } 1913 final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK; 1914 if ((compareUndefined || deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED) 1915 && deltaScreenLayoutDir != (screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) { 1916 changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; 1917 } 1918 if ((compareUndefined || delta.touchscreen != TOUCHSCREEN_UNDEFINED) 1919 && touchscreen != delta.touchscreen) { 1920 changed |= ActivityInfo.CONFIG_TOUCHSCREEN; 1921 } 1922 if ((compareUndefined || delta.keyboard != KEYBOARD_UNDEFINED) 1923 && keyboard != delta.keyboard) { 1924 changed |= ActivityInfo.CONFIG_KEYBOARD; 1925 } 1926 if ((compareUndefined || delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED) 1927 && keyboardHidden != delta.keyboardHidden) { 1928 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 1929 } 1930 if ((compareUndefined || delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED) 1931 && hardKeyboardHidden != delta.hardKeyboardHidden) { 1932 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 1933 } 1934 if ((compareUndefined || delta.navigation != NAVIGATION_UNDEFINED) 1935 && navigation != delta.navigation) { 1936 changed |= ActivityInfo.CONFIG_NAVIGATION; 1937 } 1938 if ((compareUndefined || delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED) 1939 && navigationHidden != delta.navigationHidden) { 1940 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 1941 } 1942 if ((compareUndefined || delta.orientation != ORIENTATION_UNDEFINED) 1943 && orientation != delta.orientation) { 1944 changed |= ActivityInfo.CONFIG_ORIENTATION; 1945 } 1946 if ((compareUndefined || getScreenLayoutNoDirection(delta.screenLayout) != 1947 (SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED)) 1948 && getScreenLayoutNoDirection(screenLayout) != 1949 getScreenLayoutNoDirection(delta.screenLayout)) { 1950 changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; 1951 } 1952 if ((compareUndefined || 1953 (delta.colorMode & COLOR_MODE_HDR_MASK) != COLOR_MODE_HDR_UNDEFINED) 1954 && (colorMode & COLOR_MODE_HDR_MASK) != 1955 (delta.colorMode & COLOR_MODE_HDR_MASK)) { 1956 changed |= ActivityInfo.CONFIG_COLOR_MODE; 1957 } 1958 if ((compareUndefined || 1959 (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) != 1960 COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED) 1961 && (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) != 1962 (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) { 1963 changed |= ActivityInfo.CONFIG_COLOR_MODE; 1964 } 1965 if ((compareUndefined || delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED)) 1966 && uiMode != delta.uiMode) { 1967 changed |= ActivityInfo.CONFIG_UI_MODE; 1968 } 1969 if ((compareUndefined || delta.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) 1970 && screenWidthDp != delta.screenWidthDp) { 1971 changed |= ActivityInfo.CONFIG_SCREEN_SIZE; 1972 } 1973 if ((compareUndefined || delta.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) 1974 && screenHeightDp != delta.screenHeightDp) { 1975 changed |= ActivityInfo.CONFIG_SCREEN_SIZE; 1976 } 1977 if ((compareUndefined || delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) 1978 && smallestScreenWidthDp != delta.smallestScreenWidthDp) { 1979 changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; 1980 } 1981 if ((compareUndefined || delta.densityDpi != DENSITY_DPI_UNDEFINED) 1982 && densityDpi != delta.densityDpi) { 1983 changed |= ActivityInfo.CONFIG_DENSITY; 1984 } 1985 if ((compareUndefined || delta.assetsSeq != ASSETS_SEQ_UNDEFINED) 1986 && assetsSeq != delta.assetsSeq) { 1987 changed |= ActivityInfo.CONFIG_ASSETS_PATHS; 1988 } 1989 1990 // WindowConfiguration differences aren't considered public... 1991 if (!publicOnly 1992 && windowConfiguration.diff(delta.windowConfiguration, compareUndefined) != 0) { 1993 changed |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION; 1994 } 1995 1996 if ((compareUndefined || delta.fontWeightAdjustment != FONT_WEIGHT_ADJUSTMENT_UNDEFINED) 1997 && fontWeightAdjustment != delta.fontWeightAdjustment) { 1998 changed |= ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT; 1999 } 2000 2001 if (mGrammaticalGender != delta.mGrammaticalGender) { 2002 changed |= ActivityInfo.CONFIG_GRAMMATICAL_GENDER; 2003 } 2004 return changed; 2005 } 2006 2007 /** 2008 * Determines if a new resource needs to be loaded from the bit set of 2009 * configuration changes returned by {@link #updateFrom(Configuration)}. 2010 * 2011 * @param configChanges the mask of changes configurations as returned by 2012 * {@link #updateFrom(Configuration)} 2013 * @param interestingChanges the configuration changes that the resource 2014 * can handle as given in 2015 * {@link android.util.TypedValue#changingConfigurations} 2016 * @return {@code true} if the resource needs to be loaded, {@code false} 2017 * otherwise 2018 */ needNewResources(@onfig int configChanges, @Config int interestingChanges)2019 public static boolean needNewResources(@Config int configChanges, 2020 @Config int interestingChanges) { 2021 // CONFIG_ASSETS_PATHS and CONFIG_FONT_SCALE are higher level configuration changes that 2022 // all resources are subject to change with. 2023 interestingChanges = interestingChanges | ActivityInfo.CONFIG_ASSETS_PATHS 2024 | ActivityInfo.CONFIG_FONT_SCALE; 2025 return (configChanges & interestingChanges) != 0; 2026 } 2027 2028 /** 2029 * @hide Return true if the sequence of 'other' is better than this. Assumes 2030 * that 'this' is your current sequence and 'other' is a new one you have 2031 * received some how and want to compare with what you have. 2032 */ isOtherSeqNewer(Configuration other)2033 public boolean isOtherSeqNewer(Configuration other) { 2034 if (other == null) { 2035 // Validation check. 2036 return false; 2037 } 2038 if (other.seq == 0) { 2039 // If the other sequence is not specified, then we must assume 2040 // it is newer since we don't know any better. 2041 return true; 2042 } 2043 if (seq == 0) { 2044 // If this sequence is not specified, then we also consider the 2045 // other is better. Yes we have a preference for other. Sue us. 2046 return true; 2047 } 2048 int diff = other.seq - seq; 2049 if (Math.abs(diff) > 0x10000000) { 2050 // If there has been a sufficiently large jump, assume the 2051 // sequence has wrapped around. 2052 return diff < 0; 2053 } 2054 return diff > 0; 2055 } 2056 2057 /** 2058 * Parcelable methods 2059 */ describeContents()2060 public int describeContents() { 2061 return 0; 2062 } 2063 writeToParcel(Parcel dest, int flags)2064 public void writeToParcel(Parcel dest, int flags) { 2065 dest.writeFloat(fontScale); 2066 dest.writeInt(mcc); 2067 dest.writeInt(mnc); 2068 2069 fixUpLocaleList(); 2070 dest.writeTypedObject(mLocaleList, flags); 2071 2072 if(userSetLocale) { 2073 dest.writeInt(1); 2074 } else { 2075 dest.writeInt(0); 2076 } 2077 dest.writeInt(touchscreen); 2078 dest.writeInt(keyboard); 2079 dest.writeInt(keyboardHidden); 2080 dest.writeInt(hardKeyboardHidden); 2081 dest.writeInt(navigation); 2082 dest.writeInt(navigationHidden); 2083 dest.writeInt(orientation); 2084 dest.writeInt(screenLayout); 2085 dest.writeInt(colorMode); 2086 dest.writeInt(uiMode); 2087 dest.writeInt(screenWidthDp); 2088 dest.writeInt(screenHeightDp); 2089 dest.writeInt(smallestScreenWidthDp); 2090 dest.writeInt(densityDpi); 2091 dest.writeInt(compatScreenWidthDp); 2092 dest.writeInt(compatScreenHeightDp); 2093 dest.writeInt(compatSmallestScreenWidthDp); 2094 windowConfiguration.writeToParcel(dest, flags); 2095 dest.writeInt(assetsSeq); 2096 dest.writeInt(seq); 2097 dest.writeInt(fontWeightAdjustment); 2098 dest.writeInt(mGrammaticalGender); 2099 } 2100 readFromParcel(Parcel source)2101 public void readFromParcel(Parcel source) { 2102 fontScale = source.readFloat(); 2103 mcc = source.readInt(); 2104 mnc = source.readInt(); 2105 2106 mLocaleList = source.readTypedObject(LocaleList.CREATOR); 2107 locale = mLocaleList.get(0); 2108 2109 userSetLocale = (source.readInt()==1); 2110 touchscreen = source.readInt(); 2111 keyboard = source.readInt(); 2112 keyboardHidden = source.readInt(); 2113 hardKeyboardHidden = source.readInt(); 2114 navigation = source.readInt(); 2115 navigationHidden = source.readInt(); 2116 orientation = source.readInt(); 2117 screenLayout = source.readInt(); 2118 colorMode = source.readInt(); 2119 uiMode = source.readInt(); 2120 screenWidthDp = source.readInt(); 2121 screenHeightDp = source.readInt(); 2122 smallestScreenWidthDp = source.readInt(); 2123 densityDpi = source.readInt(); 2124 compatScreenWidthDp = source.readInt(); 2125 compatScreenHeightDp = source.readInt(); 2126 compatSmallestScreenWidthDp = source.readInt(); 2127 windowConfiguration.readFromParcel(source); 2128 assetsSeq = source.readInt(); 2129 seq = source.readInt(); 2130 fontWeightAdjustment = source.readInt(); 2131 mGrammaticalGender = source.readInt(); 2132 } 2133 2134 public static final @android.annotation.NonNull Parcelable.Creator<Configuration> CREATOR 2135 = new Parcelable.Creator<Configuration>() { 2136 public Configuration createFromParcel(Parcel source) { 2137 return new Configuration(source); 2138 } 2139 2140 public Configuration[] newArray(int size) { 2141 return new Configuration[size]; 2142 } 2143 }; 2144 2145 /** 2146 * Construct this Configuration object, reading from the Parcel. 2147 */ Configuration(Parcel source)2148 private Configuration(Parcel source) { 2149 readFromParcel(source); 2150 } 2151 2152 2153 /** 2154 * Retuns whether the configuration is in night mode 2155 * @return true if night mode is active and false otherwise 2156 */ isNightModeActive()2157 public boolean isNightModeActive() { 2158 return (uiMode & UI_MODE_NIGHT_MASK) == UI_MODE_NIGHT_YES; 2159 } 2160 compareTo(Configuration that)2161 public int compareTo(Configuration that) { 2162 int n; 2163 float a = this.fontScale; 2164 float b = that.fontScale; 2165 if (a < b) return -1; 2166 if (a > b) return 1; 2167 n = this.mcc - that.mcc; 2168 if (n != 0) return n; 2169 n = this.mnc - that.mnc; 2170 if (n != 0) return n; 2171 2172 fixUpLocaleList(); 2173 that.fixUpLocaleList(); 2174 // for backward compatibility, we consider an empty locale list to be greater 2175 // than any non-empty locale list. 2176 if (this.mLocaleList.isEmpty()) { 2177 if (!that.mLocaleList.isEmpty()) return 1; 2178 } else if (that.mLocaleList.isEmpty()) { 2179 return -1; 2180 } else { 2181 final int minSize = Math.min(this.mLocaleList.size(), that.mLocaleList.size()); 2182 for (int i = 0; i < minSize; ++i) { 2183 final Locale thisLocale = this.mLocaleList.get(i); 2184 final Locale thatLocale = that.mLocaleList.get(i); 2185 n = thisLocale.getLanguage().compareTo(thatLocale.getLanguage()); 2186 if (n != 0) return n; 2187 n = thisLocale.getCountry().compareTo(thatLocale.getCountry()); 2188 if (n != 0) return n; 2189 n = thisLocale.getVariant().compareTo(thatLocale.getVariant()); 2190 if (n != 0) return n; 2191 n = thisLocale.toLanguageTag().compareTo(thatLocale.toLanguageTag()); 2192 if (n != 0) return n; 2193 } 2194 n = this.mLocaleList.size() - that.mLocaleList.size(); 2195 if (n != 0) return n; 2196 } 2197 2198 n = this.mGrammaticalGender - that.mGrammaticalGender; 2199 if (n != 0) return n; 2200 n = this.touchscreen - that.touchscreen; 2201 if (n != 0) return n; 2202 n = this.keyboard - that.keyboard; 2203 if (n != 0) return n; 2204 n = this.keyboardHidden - that.keyboardHidden; 2205 if (n != 0) return n; 2206 n = this.hardKeyboardHidden - that.hardKeyboardHidden; 2207 if (n != 0) return n; 2208 n = this.navigation - that.navigation; 2209 if (n != 0) return n; 2210 n = this.navigationHidden - that.navigationHidden; 2211 if (n != 0) return n; 2212 n = this.orientation - that.orientation; 2213 if (n != 0) return n; 2214 n = this.colorMode - that.colorMode; 2215 if (n != 0) return n; 2216 n = this.screenLayout - that.screenLayout; 2217 if (n != 0) return n; 2218 n = this.uiMode - that.uiMode; 2219 if (n != 0) return n; 2220 n = this.screenWidthDp - that.screenWidthDp; 2221 if (n != 0) return n; 2222 n = this.screenHeightDp - that.screenHeightDp; 2223 if (n != 0) return n; 2224 n = this.smallestScreenWidthDp - that.smallestScreenWidthDp; 2225 if (n != 0) return n; 2226 n = this.densityDpi - that.densityDpi; 2227 if (n != 0) return n; 2228 n = this.assetsSeq - that.assetsSeq; 2229 if (n != 0) return n; 2230 n = windowConfiguration.compareTo(that.windowConfiguration); 2231 if (n != 0) return n; 2232 n = this.fontWeightAdjustment - that.fontWeightAdjustment; 2233 return n; 2234 } 2235 equals(Configuration that)2236 public boolean equals(Configuration that) { 2237 if (that == null) return false; 2238 if (that == this) return true; 2239 return this.compareTo(that) == 0; 2240 } 2241 equals(@ullable Object that)2242 public boolean equals(@Nullable Object that) { 2243 try { 2244 return equals((Configuration)that); 2245 } catch (ClassCastException e) { 2246 } 2247 return false; 2248 } 2249 hashCode()2250 public int hashCode() { 2251 int result = 17; 2252 result = 31 * result + Float.floatToIntBits(fontScale); 2253 result = 31 * result + mcc; 2254 result = 31 * result + mnc; 2255 result = 31 * result + mLocaleList.hashCode(); 2256 result = 31 * result + touchscreen; 2257 result = 31 * result + keyboard; 2258 result = 31 * result + keyboardHidden; 2259 result = 31 * result + hardKeyboardHidden; 2260 result = 31 * result + navigation; 2261 result = 31 * result + navigationHidden; 2262 result = 31 * result + orientation; 2263 result = 31 * result + screenLayout; 2264 result = 31 * result + colorMode; 2265 result = 31 * result + uiMode; 2266 result = 31 * result + screenWidthDp; 2267 result = 31 * result + screenHeightDp; 2268 result = 31 * result + smallestScreenWidthDp; 2269 result = 31 * result + densityDpi; 2270 result = 31 * result + assetsSeq; 2271 result = 31 * result + fontWeightAdjustment; 2272 result = 31 * result + mGrammaticalGender; 2273 return result; 2274 } 2275 2276 /** 2277 * Returns the user preference for the grammatical gender. Will be 2278 * {@link #GRAMMATICAL_GENDER_NOT_SPECIFIED} or 2279 * {@link #GRAMMATICAL_GENDER_NEUTRAL} or 2280 * {@link #GRAMMATICAL_GENDER_FEMININE} or 2281 * {@link #GRAMMATICAL_GENDER_MASCULINE}. 2282 * 2283 * @return The preferred grammatical gender. 2284 */ 2285 @GrammaticalGender getGrammaticalGender()2286 public int getGrammaticalGender() { 2287 return mGrammaticalGender; 2288 } 2289 2290 /** 2291 * Sets the user preference for the grammatical gender. This is only for frameworks to easily 2292 * override the gender in the configuration. To update the grammatical gender for an application 2293 * use {@link GrammaticalInflectionManager#setRequestedApplicationGrammaticalGender(int)}. 2294 * 2295 * @param grammaticalGender The preferred grammatical gender. 2296 * @hide 2297 */ setGrammaticalGender(@rammaticalGender int grammaticalGender)2298 public void setGrammaticalGender(@GrammaticalGender int grammaticalGender) { 2299 mGrammaticalGender = grammaticalGender; 2300 } 2301 2302 /** 2303 * Get the locale list. This is the preferred way for getting the locales (instead of using 2304 * the direct accessor to {@link #locale}, which would only provide the primary locale). 2305 * 2306 * @return The locale list. 2307 */ getLocales()2308 public @NonNull LocaleList getLocales() { 2309 fixUpLocaleList(); 2310 return mLocaleList; 2311 } 2312 2313 /** 2314 * Set the locale list. This is the preferred way for setting up the locales (instead of using 2315 * the direct accessor or {@link #setLocale(Locale)}). This will also set the layout direction 2316 * according to the first locale in the list. 2317 * 2318 * Note that the layout direction will always come from the first locale in the locale list, 2319 * even if the locale is not supported by the resources (the resources may only support 2320 * another locale further down the list which has a different direction). 2321 * 2322 * @param locales The locale list. If null, an empty LocaleList will be assigned. 2323 */ setLocales(@ullable LocaleList locales)2324 public void setLocales(@Nullable LocaleList locales) { 2325 mLocaleList = locales == null ? LocaleList.getEmptyLocaleList() : locales; 2326 locale = mLocaleList.get(0); 2327 setLayoutDirection(locale); 2328 } 2329 2330 /** 2331 * Set the locale list to a list of just one locale. This will also set the layout direction 2332 * according to the locale. 2333 * 2334 * Note that after this is run, calling <code>.equals()</code> on the input locale and the 2335 * {@link #locale} attribute would return <code>true</code> if they are not null, but there is 2336 * no guarantee that they would be the same object. 2337 * 2338 * See also the note about layout direction in {@link #setLocales(LocaleList)}. 2339 * 2340 * @param loc The locale. Can be null. 2341 */ setLocale(@ullable Locale loc)2342 public void setLocale(@Nullable Locale loc) { 2343 setLocales(loc == null ? LocaleList.getEmptyLocaleList() : new LocaleList(loc)); 2344 } 2345 2346 /** 2347 * @hide 2348 * 2349 * Clears the locale without changing layout direction. 2350 */ clearLocales()2351 public void clearLocales() { 2352 mLocaleList = LocaleList.getEmptyLocaleList(); 2353 locale = null; 2354 } 2355 2356 /** 2357 * Return the layout direction. Will be either {@link View#LAYOUT_DIRECTION_LTR} or 2358 * {@link View#LAYOUT_DIRECTION_RTL}. 2359 * 2360 * @return Returns {@link View#LAYOUT_DIRECTION_RTL} if the configuration 2361 * is {@link #SCREENLAYOUT_LAYOUTDIR_RTL}, otherwise {@link View#LAYOUT_DIRECTION_LTR}. 2362 */ getLayoutDirection()2363 public int getLayoutDirection() { 2364 return (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK) == SCREENLAYOUT_LAYOUTDIR_RTL 2365 ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR; 2366 } 2367 2368 /** 2369 * Set the layout direction from a Locale. 2370 * 2371 * @param loc The Locale. If null will set the layout direction to 2372 * {@link View#LAYOUT_DIRECTION_LTR}. If not null will set it to the layout direction 2373 * corresponding to the Locale. 2374 * 2375 * @see View#LAYOUT_DIRECTION_LTR 2376 * @see View#LAYOUT_DIRECTION_RTL 2377 */ setLayoutDirection(Locale loc)2378 public void setLayoutDirection(Locale loc) { 2379 // There is a "1" difference between the configuration values for 2380 // layout direction and View constants for layout direction, just add "1". 2381 final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(loc); 2382 screenLayout = (screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK)| 2383 (layoutDirection << SCREENLAYOUT_LAYOUTDIR_SHIFT); 2384 } 2385 getScreenLayoutNoDirection(int screenLayout)2386 private static int getScreenLayoutNoDirection(int screenLayout) { 2387 return screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK; 2388 } 2389 2390 /** 2391 * Return whether the screen has a round shape. Apps may choose to change styling based 2392 * on this property, such as the alignment or layout of text or informational icons. 2393 * 2394 * @return true if the screen is rounded, false otherwise 2395 */ isScreenRound()2396 public boolean isScreenRound() { 2397 return (screenLayout & SCREENLAYOUT_ROUND_MASK) == SCREENLAYOUT_ROUND_YES; 2398 } 2399 2400 /** 2401 * Return whether the screen has a wide color gamut and wide color gamut rendering 2402 * is supported by this device. 2403 * 2404 * When true, it implies the screen is colorspace aware but not 2405 * necessarily color-managed. The final colors may still be changed by the 2406 * screen depending on user settings. 2407 * 2408 * @return true if the screen has a wide color gamut and wide color gamut rendering 2409 * is supported, false otherwise 2410 */ isScreenWideColorGamut()2411 public boolean isScreenWideColorGamut() { 2412 return (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) == COLOR_MODE_WIDE_COLOR_GAMUT_YES; 2413 } 2414 2415 /** 2416 * Return whether the screen has a high dynamic range. 2417 * 2418 * @return true if the screen has a high dynamic range, false otherwise 2419 */ isScreenHdr()2420 public boolean isScreenHdr() { 2421 return (colorMode & COLOR_MODE_HDR_MASK) == COLOR_MODE_HDR_YES; 2422 } 2423 2424 /** 2425 * 2426 * @hide 2427 */ localesToResourceQualifier(LocaleList locs)2428 public static String localesToResourceQualifier(LocaleList locs) { 2429 final StringBuilder sb = new StringBuilder(); 2430 for (int i = 0; i < locs.size(); i++) { 2431 final Locale loc = locs.get(i); 2432 final int l = loc.getLanguage().length(); 2433 if (l == 0) { 2434 continue; 2435 } 2436 final int s = loc.getScript().length(); 2437 final int c = loc.getCountry().length(); 2438 final int v = loc.getVariant().length(); 2439 // We ignore locale extensions, since they are not supported by AAPT 2440 2441 if (sb.length() != 0) { 2442 sb.append(","); 2443 } 2444 if (l == 2 && s == 0 && (c == 0 || c == 2) && v == 0) { 2445 // Traditional locale format: xx or xx-rYY 2446 sb.append(loc.getLanguage()); 2447 if (c == 2) { 2448 sb.append("-r").append(loc.getCountry()); 2449 } 2450 } else { 2451 sb.append("b+"); 2452 sb.append(loc.getLanguage()); 2453 if (s != 0) { 2454 sb.append("+"); 2455 sb.append(loc.getScript()); 2456 } 2457 if (c != 0) { 2458 sb.append("+"); 2459 sb.append(loc.getCountry()); 2460 } 2461 if (v != 0) { 2462 sb.append("+"); 2463 sb.append(loc.getVariant()); 2464 } 2465 } 2466 } 2467 return sb.toString(); 2468 } 2469 2470 2471 /** 2472 * Returns a string representation of the configuration that can be parsed 2473 * by build tools (like AAPT), without display metrics included 2474 * 2475 * @hide 2476 */ 2477 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) resourceQualifierString(Configuration config)2478 public static String resourceQualifierString(Configuration config) { 2479 return resourceQualifierString(config, null); 2480 } 2481 2482 /** 2483 * Returns a string representation of the configuration that can be parsed 2484 * by build tools (like AAPT). 2485 * 2486 * @hide 2487 */ resourceQualifierString(Configuration config, DisplayMetrics metrics)2488 public static String resourceQualifierString(Configuration config, DisplayMetrics metrics) { 2489 ArrayList<String> parts = new ArrayList<String>(); 2490 2491 if (config.mcc != 0) { 2492 parts.add("mcc" + config.mcc); 2493 if (config.mnc != 0) { 2494 parts.add("mnc" + config.mnc); 2495 } 2496 } 2497 2498 if (!config.mLocaleList.isEmpty()) { 2499 final String resourceQualifier = localesToResourceQualifier(config.mLocaleList); 2500 if (!resourceQualifier.isEmpty()) { 2501 parts.add(resourceQualifier); 2502 } 2503 } 2504 2505 switch (config.mGrammaticalGender) { 2506 case Configuration.GRAMMATICAL_GENDER_NEUTRAL: 2507 parts.add("neuter"); 2508 break; 2509 case Configuration.GRAMMATICAL_GENDER_FEMININE: 2510 parts.add("feminine"); 2511 break; 2512 case Configuration.GRAMMATICAL_GENDER_MASCULINE: 2513 parts.add("masculine"); 2514 break; 2515 default: 2516 break; 2517 } 2518 2519 switch (config.screenLayout & Configuration.SCREENLAYOUT_LAYOUTDIR_MASK) { 2520 case Configuration.SCREENLAYOUT_LAYOUTDIR_LTR: 2521 parts.add("ldltr"); 2522 break; 2523 case Configuration.SCREENLAYOUT_LAYOUTDIR_RTL: 2524 parts.add("ldrtl"); 2525 break; 2526 default: 2527 break; 2528 } 2529 2530 if (config.smallestScreenWidthDp != 0) { 2531 parts.add("sw" + config.smallestScreenWidthDp + "dp"); 2532 } 2533 2534 if (config.screenWidthDp != 0) { 2535 parts.add("w" + config.screenWidthDp + "dp"); 2536 } 2537 2538 if (config.screenHeightDp != 0) { 2539 parts.add("h" + config.screenHeightDp + "dp"); 2540 } 2541 2542 switch (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) { 2543 case Configuration.SCREENLAYOUT_SIZE_SMALL: 2544 parts.add("small"); 2545 break; 2546 case Configuration.SCREENLAYOUT_SIZE_NORMAL: 2547 parts.add("normal"); 2548 break; 2549 case Configuration.SCREENLAYOUT_SIZE_LARGE: 2550 parts.add("large"); 2551 break; 2552 case Configuration.SCREENLAYOUT_SIZE_XLARGE: 2553 parts.add("xlarge"); 2554 break; 2555 default: 2556 break; 2557 } 2558 2559 switch (config.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK) { 2560 case Configuration.SCREENLAYOUT_LONG_YES: 2561 parts.add("long"); 2562 break; 2563 case Configuration.SCREENLAYOUT_LONG_NO: 2564 parts.add("notlong"); 2565 break; 2566 default: 2567 break; 2568 } 2569 2570 switch (config.screenLayout & Configuration.SCREENLAYOUT_ROUND_MASK) { 2571 case Configuration.SCREENLAYOUT_ROUND_YES: 2572 parts.add("round"); 2573 break; 2574 case Configuration.SCREENLAYOUT_ROUND_NO: 2575 parts.add("notround"); 2576 break; 2577 default: 2578 break; 2579 } 2580 2581 switch (config.colorMode & Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_MASK) { 2582 case Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_YES: 2583 parts.add("widecg"); 2584 break; 2585 case Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_NO: 2586 parts.add("nowidecg"); 2587 break; 2588 default: 2589 break; 2590 } 2591 2592 switch (config.colorMode & Configuration.COLOR_MODE_HDR_MASK) { 2593 case Configuration.COLOR_MODE_HDR_YES: 2594 parts.add("highdr"); 2595 break; 2596 case Configuration.COLOR_MODE_HDR_NO: 2597 parts.add("lowdr"); 2598 break; 2599 default: 2600 break; 2601 } 2602 2603 switch (config.orientation) { 2604 case Configuration.ORIENTATION_LANDSCAPE: 2605 parts.add("land"); 2606 break; 2607 case Configuration.ORIENTATION_PORTRAIT: 2608 parts.add("port"); 2609 break; 2610 default: 2611 break; 2612 } 2613 2614 final String uiModeTypeString = 2615 getUiModeTypeString(config.uiMode & Configuration.UI_MODE_TYPE_MASK); 2616 if (uiModeTypeString != null) { 2617 parts.add(uiModeTypeString); 2618 } 2619 2620 switch (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) { 2621 case Configuration.UI_MODE_NIGHT_YES: 2622 parts.add("night"); 2623 break; 2624 case Configuration.UI_MODE_NIGHT_NO: 2625 parts.add("notnight"); 2626 break; 2627 default: 2628 break; 2629 } 2630 2631 switch (config.densityDpi) { 2632 case DENSITY_DPI_UNDEFINED: 2633 break; 2634 case 120: 2635 parts.add("ldpi"); 2636 break; 2637 case 160: 2638 parts.add("mdpi"); 2639 break; 2640 case 213: 2641 parts.add("tvdpi"); 2642 break; 2643 case 240: 2644 parts.add("hdpi"); 2645 break; 2646 case 320: 2647 parts.add("xhdpi"); 2648 break; 2649 case 480: 2650 parts.add("xxhdpi"); 2651 break; 2652 case 640: 2653 parts.add("xxxhdpi"); 2654 break; 2655 case DENSITY_DPI_ANY: 2656 parts.add("anydpi"); 2657 break; 2658 case DENSITY_DPI_NONE: 2659 parts.add("nodpi"); 2660 break; 2661 default: 2662 parts.add(config.densityDpi + "dpi"); 2663 break; 2664 } 2665 2666 switch (config.touchscreen) { 2667 case Configuration.TOUCHSCREEN_NOTOUCH: 2668 parts.add("notouch"); 2669 break; 2670 case Configuration.TOUCHSCREEN_FINGER: 2671 parts.add("finger"); 2672 break; 2673 default: 2674 break; 2675 } 2676 2677 switch (config.keyboardHidden) { 2678 case Configuration.KEYBOARDHIDDEN_NO: 2679 parts.add("keysexposed"); 2680 break; 2681 case Configuration.KEYBOARDHIDDEN_YES: 2682 parts.add("keyshidden"); 2683 break; 2684 case Configuration.KEYBOARDHIDDEN_SOFT: 2685 parts.add("keyssoft"); 2686 break; 2687 default: 2688 break; 2689 } 2690 2691 switch (config.keyboard) { 2692 case Configuration.KEYBOARD_NOKEYS: 2693 parts.add("nokeys"); 2694 break; 2695 case Configuration.KEYBOARD_QWERTY: 2696 parts.add("qwerty"); 2697 break; 2698 case Configuration.KEYBOARD_12KEY: 2699 parts.add("12key"); 2700 break; 2701 default: 2702 break; 2703 } 2704 2705 switch (config.navigationHidden) { 2706 case Configuration.NAVIGATIONHIDDEN_NO: 2707 parts.add("navexposed"); 2708 break; 2709 case Configuration.NAVIGATIONHIDDEN_YES: 2710 parts.add("navhidden"); 2711 break; 2712 default: 2713 break; 2714 } 2715 2716 switch (config.navigation) { 2717 case Configuration.NAVIGATION_NONAV: 2718 parts.add("nonav"); 2719 break; 2720 case Configuration.NAVIGATION_DPAD: 2721 parts.add("dpad"); 2722 break; 2723 case Configuration.NAVIGATION_TRACKBALL: 2724 parts.add("trackball"); 2725 break; 2726 case Configuration.NAVIGATION_WHEEL: 2727 parts.add("wheel"); 2728 break; 2729 default: 2730 break; 2731 } 2732 2733 if (metrics != null) { 2734 final int width, height; 2735 if (metrics.widthPixels >= metrics.heightPixels) { 2736 width = metrics.widthPixels; 2737 height = metrics.heightPixels; 2738 } else { 2739 //noinspection SuspiciousNameCombination 2740 width = metrics.heightPixels; 2741 //noinspection SuspiciousNameCombination 2742 height = metrics.widthPixels; 2743 } 2744 parts.add(width + "x" + height); 2745 } 2746 2747 parts.add("v" + Build.VERSION.RESOURCES_SDK_INT); 2748 return TextUtils.join("-", parts); 2749 } 2750 2751 /** 2752 * @hide 2753 */ getUiModeTypeString(int uiModeType)2754 public static String getUiModeTypeString(int uiModeType) { 2755 switch (uiModeType) { 2756 case Configuration.UI_MODE_TYPE_APPLIANCE: 2757 return "appliance"; 2758 case Configuration.UI_MODE_TYPE_DESK: 2759 return "desk"; 2760 case Configuration.UI_MODE_TYPE_TELEVISION: 2761 return "television"; 2762 case Configuration.UI_MODE_TYPE_CAR: 2763 return "car"; 2764 case Configuration.UI_MODE_TYPE_WATCH: 2765 return "watch"; 2766 case Configuration.UI_MODE_TYPE_VR_HEADSET: 2767 return "vrheadset"; 2768 default: 2769 return null; 2770 } 2771 } 2772 2773 /** 2774 * Generate a delta Configuration between <code>base</code> and <code>change</code>. The 2775 * resulting delta can be used with {@link #updateFrom(Configuration)}. 2776 * <p /> 2777 * Caveat: If the any of the Configuration's members becomes undefined, then 2778 * {@link #updateFrom(Configuration)} will treat it as a no-op and not update that member. 2779 * 2780 * This is fine for device configurations as no member is ever undefined. 2781 */ 2782 @NonNull generateDelta( @onNull Configuration base, @NonNull Configuration change)2783 public static Configuration generateDelta( 2784 @NonNull Configuration base, @NonNull Configuration change) { 2785 final Configuration delta = new Configuration(); 2786 if (base.fontScale != change.fontScale) { 2787 delta.fontScale = change.fontScale; 2788 } 2789 2790 if (base.mcc != change.mcc) { 2791 delta.mcc = change.mcc; 2792 } 2793 2794 if (base.mnc != change.mnc) { 2795 delta.mnc = change.mnc; 2796 } 2797 2798 base.fixUpLocaleList(); 2799 change.fixUpLocaleList(); 2800 if (!base.mLocaleList.equals(change.mLocaleList)) { 2801 delta.mLocaleList = change.mLocaleList; 2802 delta.locale = change.locale; 2803 } 2804 2805 if (base.mGrammaticalGender != change.mGrammaticalGender) { 2806 delta.mGrammaticalGender = change.mGrammaticalGender; 2807 } 2808 2809 if (base.touchscreen != change.touchscreen) { 2810 delta.touchscreen = change.touchscreen; 2811 } 2812 2813 if (base.keyboard != change.keyboard) { 2814 delta.keyboard = change.keyboard; 2815 } 2816 2817 if (base.keyboardHidden != change.keyboardHidden) { 2818 delta.keyboardHidden = change.keyboardHidden; 2819 } 2820 2821 if (base.navigation != change.navigation) { 2822 delta.navigation = change.navigation; 2823 } 2824 2825 if (base.navigationHidden != change.navigationHidden) { 2826 delta.navigationHidden = change.navigationHidden; 2827 } 2828 2829 if (base.orientation != change.orientation) { 2830 delta.orientation = change.orientation; 2831 } 2832 2833 if ((base.screenLayout & SCREENLAYOUT_SIZE_MASK) != 2834 (change.screenLayout & SCREENLAYOUT_SIZE_MASK)) { 2835 delta.screenLayout |= change.screenLayout & SCREENLAYOUT_SIZE_MASK; 2836 } 2837 2838 if ((base.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK) != 2839 (change.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) { 2840 delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK; 2841 } 2842 2843 if ((base.screenLayout & SCREENLAYOUT_LONG_MASK) != 2844 (change.screenLayout & SCREENLAYOUT_LONG_MASK)) { 2845 delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LONG_MASK; 2846 } 2847 2848 if ((base.screenLayout & SCREENLAYOUT_ROUND_MASK) != 2849 (change.screenLayout & SCREENLAYOUT_ROUND_MASK)) { 2850 delta.screenLayout |= change.screenLayout & SCREENLAYOUT_ROUND_MASK; 2851 } 2852 2853 if ((base.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) != 2854 (change.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) { 2855 delta.colorMode |= change.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK; 2856 } 2857 2858 if ((base.colorMode & COLOR_MODE_HDR_MASK) != 2859 (change.colorMode & COLOR_MODE_HDR_MASK)) { 2860 delta.colorMode |= change.colorMode & COLOR_MODE_HDR_MASK; 2861 } 2862 2863 if ((base.uiMode & UI_MODE_TYPE_MASK) != (change.uiMode & UI_MODE_TYPE_MASK)) { 2864 delta.uiMode |= change.uiMode & UI_MODE_TYPE_MASK; 2865 } 2866 2867 if ((base.uiMode & UI_MODE_NIGHT_MASK) != (change.uiMode & UI_MODE_NIGHT_MASK)) { 2868 delta.uiMode |= change.uiMode & UI_MODE_NIGHT_MASK; 2869 } 2870 2871 if (base.screenWidthDp != change.screenWidthDp) { 2872 delta.screenWidthDp = change.screenWidthDp; 2873 } 2874 2875 if (base.screenHeightDp != change.screenHeightDp) { 2876 delta.screenHeightDp = change.screenHeightDp; 2877 } 2878 2879 if (base.smallestScreenWidthDp != change.smallestScreenWidthDp) { 2880 delta.smallestScreenWidthDp = change.smallestScreenWidthDp; 2881 } 2882 2883 if (base.densityDpi != change.densityDpi) { 2884 delta.densityDpi = change.densityDpi; 2885 } 2886 2887 if (base.assetsSeq != change.assetsSeq) { 2888 delta.assetsSeq = change.assetsSeq; 2889 } 2890 2891 if (!base.windowConfiguration.equals(change.windowConfiguration)) { 2892 delta.windowConfiguration.setTo(change.windowConfiguration); 2893 } 2894 2895 if (base.fontWeightAdjustment != change.fontWeightAdjustment) { 2896 delta.fontWeightAdjustment = change.fontWeightAdjustment; 2897 } 2898 return delta; 2899 } 2900 2901 private static final String XML_ATTR_FONT_SCALE = "fs"; 2902 private static final String XML_ATTR_MCC = "mcc"; 2903 private static final String XML_ATTR_MNC = "mnc"; 2904 private static final String XML_ATTR_LOCALES = "locales"; 2905 private static final String XML_ATTR_TOUCHSCREEN = "touch"; 2906 private static final String XML_ATTR_KEYBOARD = "key"; 2907 private static final String XML_ATTR_KEYBOARD_HIDDEN = "keyHid"; 2908 private static final String XML_ATTR_HARD_KEYBOARD_HIDDEN = "hardKeyHid"; 2909 private static final String XML_ATTR_NAVIGATION = "nav"; 2910 private static final String XML_ATTR_NAVIGATION_HIDDEN = "navHid"; 2911 private static final String XML_ATTR_ORIENTATION = "ori"; 2912 private static final String XML_ATTR_ROTATION = "rot"; 2913 private static final String XML_ATTR_SCREEN_LAYOUT = "scrLay"; 2914 private static final String XML_ATTR_COLOR_MODE = "clrMod"; 2915 private static final String XML_ATTR_UI_MODE = "ui"; 2916 private static final String XML_ATTR_SCREEN_WIDTH = "width"; 2917 private static final String XML_ATTR_SCREEN_HEIGHT = "height"; 2918 private static final String XML_ATTR_SMALLEST_WIDTH = "sw"; 2919 private static final String XML_ATTR_DENSITY = "density"; 2920 private static final String XML_ATTR_APP_BOUNDS = "app_bounds"; 2921 private static final String XML_ATTR_FONT_WEIGHT_ADJUSTMENT = "fontWeightAdjustment"; 2922 private static final String XML_ATTR_GRAMMATICAL_GENDER = "grammaticalGender"; 2923 2924 /** 2925 * Reads the attributes corresponding to Configuration member fields from the Xml parser. 2926 * The parser is expected to be on a tag which has Configuration attributes. 2927 * 2928 * @param parser The Xml parser from which to read attributes. 2929 * @param configOut The Configuration to populate from the Xml attributes. 2930 * {@hide} 2931 */ readXmlAttrs(XmlPullParser parser, Configuration configOut)2932 public static void readXmlAttrs(XmlPullParser parser, Configuration configOut) 2933 throws XmlPullParserException, IOException { 2934 configOut.fontScale = Float.intBitsToFloat( 2935 XmlUtils.readIntAttribute(parser, XML_ATTR_FONT_SCALE, 0)); 2936 configOut.mcc = XmlUtils.readIntAttribute(parser, XML_ATTR_MCC, 0); 2937 configOut.mnc = XmlUtils.readIntAttribute(parser, XML_ATTR_MNC, 0); 2938 2939 final String localesStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALES); 2940 configOut.mLocaleList = LocaleList.forLanguageTags(localesStr); 2941 configOut.locale = configOut.mLocaleList.get(0); 2942 2943 configOut.touchscreen = XmlUtils.readIntAttribute(parser, XML_ATTR_TOUCHSCREEN, 2944 TOUCHSCREEN_UNDEFINED); 2945 configOut.keyboard = XmlUtils.readIntAttribute(parser, XML_ATTR_KEYBOARD, 2946 KEYBOARD_UNDEFINED); 2947 configOut.keyboardHidden = XmlUtils.readIntAttribute(parser, XML_ATTR_KEYBOARD_HIDDEN, 2948 KEYBOARDHIDDEN_UNDEFINED); 2949 configOut.hardKeyboardHidden = 2950 XmlUtils.readIntAttribute(parser, XML_ATTR_HARD_KEYBOARD_HIDDEN, 2951 HARDKEYBOARDHIDDEN_UNDEFINED); 2952 configOut.navigation = XmlUtils.readIntAttribute(parser, XML_ATTR_NAVIGATION, 2953 NAVIGATION_UNDEFINED); 2954 configOut.navigationHidden = XmlUtils.readIntAttribute(parser, XML_ATTR_NAVIGATION_HIDDEN, 2955 NAVIGATIONHIDDEN_UNDEFINED); 2956 configOut.orientation = XmlUtils.readIntAttribute(parser, XML_ATTR_ORIENTATION, 2957 ORIENTATION_UNDEFINED); 2958 configOut.screenLayout = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_LAYOUT, 2959 SCREENLAYOUT_UNDEFINED); 2960 configOut.colorMode = XmlUtils.readIntAttribute(parser, XML_ATTR_COLOR_MODE, 2961 COLOR_MODE_UNDEFINED); 2962 configOut.uiMode = XmlUtils.readIntAttribute(parser, XML_ATTR_UI_MODE, 0); 2963 configOut.screenWidthDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_WIDTH, 2964 SCREEN_WIDTH_DP_UNDEFINED); 2965 configOut.screenHeightDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_HEIGHT, 2966 SCREEN_HEIGHT_DP_UNDEFINED); 2967 configOut.smallestScreenWidthDp = 2968 XmlUtils.readIntAttribute(parser, XML_ATTR_SMALLEST_WIDTH, 2969 SMALLEST_SCREEN_WIDTH_DP_UNDEFINED); 2970 configOut.densityDpi = XmlUtils.readIntAttribute(parser, XML_ATTR_DENSITY, 2971 DENSITY_DPI_UNDEFINED); 2972 configOut.fontWeightAdjustment = XmlUtils.readIntAttribute(parser, 2973 XML_ATTR_FONT_WEIGHT_ADJUSTMENT, FONT_WEIGHT_ADJUSTMENT_UNDEFINED); 2974 configOut.mGrammaticalGender = XmlUtils.readIntAttribute(parser, 2975 XML_ATTR_GRAMMATICAL_GENDER, GRAMMATICAL_GENDER_NOT_SPECIFIED); 2976 2977 // For persistence, we don't care about assetsSeq and WindowConfiguration, so do not read it 2978 // out. 2979 } 2980 } 2981