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