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