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