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