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