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 current width of the available screen space, in dp units, 755 * corresponding to 756 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenWidthQualifier">screen 757 * width</a> resource qualifier. Set to 758 * {@link #SCREEN_WIDTH_DP_UNDEFINED} if no width is specified. 759 */ 760 public int screenWidthDp; 761 762 /** 763 * Default value for {@link #screenHeightDp} indicating that no width 764 * has been specified. 765 */ 766 public static final int SCREEN_HEIGHT_DP_UNDEFINED = 0; 767 768 /** 769 * The current height of the available screen space, in dp units, 770 * corresponding to 771 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenHeightQualifier">screen 772 * height</a> resource qualifier. Set to 773 * {@link #SCREEN_HEIGHT_DP_UNDEFINED} if no height is specified. 774 */ 775 public int screenHeightDp; 776 777 /** 778 * Default value for {@link #smallestScreenWidthDp} indicating that no width 779 * has been specified. 780 */ 781 public static final int SMALLEST_SCREEN_WIDTH_DP_UNDEFINED = 0; 782 783 /** 784 * The smallest screen size an application will see in normal operation, 785 * corresponding to 786 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#SmallestScreenWidthQualifier">smallest 787 * screen width</a> resource qualifier. 788 * This is the smallest value of both screenWidthDp and screenHeightDp 789 * in both portrait and landscape. Set to 790 * {@link #SMALLEST_SCREEN_WIDTH_DP_UNDEFINED} if no width is specified. 791 */ 792 public int smallestScreenWidthDp; 793 794 /** 795 * Default value for {@link #densityDpi} indicating that no width 796 * has been specified. 797 */ 798 public static final int DENSITY_DPI_UNDEFINED = 0; 799 800 /** 801 * Value for {@link #densityDpi} for resources that scale to any density (vector drawables). 802 * {@hide} 803 */ 804 public static final int DENSITY_DPI_ANY = 0xfffe; 805 806 /** 807 * Value for {@link #densityDpi} for resources that are not meant to be scaled. 808 * {@hide} 809 */ 810 public static final int DENSITY_DPI_NONE = 0xffff; 811 812 /** 813 * The target screen density being rendered to, 814 * corresponding to 815 * <a href="{@docRoot}guide/topics/resources/providing-resources.html#DensityQualifier">density</a> 816 * resource qualifier. Set to 817 * {@link #DENSITY_DPI_UNDEFINED} if no density is specified. 818 */ 819 public int densityDpi; 820 821 /** @hide Hack to get this information from WM to app running in compat mode. */ 822 public int compatScreenWidthDp; 823 /** @hide Hack to get this information from WM to app running in compat mode. */ 824 public int compatScreenHeightDp; 825 /** @hide Hack to get this information from WM to app running in compat mode. */ 826 public int compatSmallestScreenWidthDp; 827 828 /** 829 * An undefined assetsSeq. This will not override an existing assetsSeq. 830 * @hide 831 */ 832 public static final int ASSETS_SEQ_UNDEFINED = 0; 833 834 /** 835 * Internal counter that allows us to piggyback off the configuration change mechanism to 836 * signal to apps that the the assets for an Application have changed. A difference in these 837 * between two Configurations will yield a diff flag of 838 * {@link ActivityInfo#CONFIG_ASSETS_PATHS}. 839 * @hide 840 */ 841 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 842 @TestApi 843 public int assetsSeq; 844 845 /** 846 * @hide Internal book-keeping. 847 */ 848 @UnsupportedAppUsage 849 public int seq; 850 851 /** @hide */ 852 @IntDef(flag = true, prefix = { "NATIVE_CONFIG_" }, value = { 853 NATIVE_CONFIG_MCC, 854 NATIVE_CONFIG_MNC, 855 NATIVE_CONFIG_LOCALE, 856 NATIVE_CONFIG_TOUCHSCREEN, 857 NATIVE_CONFIG_KEYBOARD, 858 NATIVE_CONFIG_KEYBOARD_HIDDEN, 859 NATIVE_CONFIG_NAVIGATION, 860 NATIVE_CONFIG_ORIENTATION, 861 NATIVE_CONFIG_DENSITY, 862 NATIVE_CONFIG_SCREEN_SIZE, 863 NATIVE_CONFIG_VERSION, 864 NATIVE_CONFIG_SCREEN_LAYOUT, 865 NATIVE_CONFIG_UI_MODE, 866 NATIVE_CONFIG_SMALLEST_SCREEN_SIZE, 867 NATIVE_CONFIG_LAYOUTDIR, 868 NATIVE_CONFIG_COLOR_MODE, 869 }) 870 @Retention(RetentionPolicy.SOURCE) 871 public @interface NativeConfig {} 872 873 /** @hide Native-specific bit mask for MCC config; DO NOT USE UNLESS YOU ARE SURE. */ 874 public static final int NATIVE_CONFIG_MCC = 0x0001; 875 /** @hide Native-specific bit mask for MNC config; DO NOT USE UNLESS YOU ARE SURE. */ 876 public static final int NATIVE_CONFIG_MNC = 0x0002; 877 /** @hide Native-specific bit mask for LOCALE config; DO NOT USE UNLESS YOU ARE SURE. */ 878 public static final int NATIVE_CONFIG_LOCALE = 0x0004; 879 /** @hide Native-specific bit mask for TOUCHSCREEN config; DO NOT USE UNLESS YOU ARE SURE. */ 880 public static final int NATIVE_CONFIG_TOUCHSCREEN = 0x0008; 881 /** @hide Native-specific bit mask for KEYBOARD config; DO NOT USE UNLESS YOU ARE SURE. */ 882 public static final int NATIVE_CONFIG_KEYBOARD = 0x0010; 883 /** @hide Native-specific bit mask for KEYBOARD_HIDDEN config; DO NOT USE UNLESS YOU 884 * ARE SURE. */ 885 public static final int NATIVE_CONFIG_KEYBOARD_HIDDEN = 0x0020; 886 /** @hide Native-specific bit mask for NAVIGATION config; DO NOT USE UNLESS YOU ARE SURE. */ 887 public static final int NATIVE_CONFIG_NAVIGATION = 0x0040; 888 /** @hide Native-specific bit mask for ORIENTATION config; DO NOT USE UNLESS YOU ARE SURE. */ 889 public static final int NATIVE_CONFIG_ORIENTATION = 0x0080; 890 /** @hide Native-specific bit mask for DENSITY config; DO NOT USE UNLESS YOU ARE SURE. */ 891 public static final int NATIVE_CONFIG_DENSITY = 0x0100; 892 /** @hide Native-specific bit mask for SCREEN_SIZE config; DO NOT USE UNLESS YOU ARE SURE. */ 893 public static final int NATIVE_CONFIG_SCREEN_SIZE = 0x0200; 894 /** @hide Native-specific bit mask for VERSION config; DO NOT USE UNLESS YOU ARE SURE. */ 895 public static final int NATIVE_CONFIG_VERSION = 0x0400; 896 /** @hide Native-specific bit mask for SCREEN_LAYOUT config; DO NOT USE UNLESS YOU ARE SURE. */ 897 public static final int NATIVE_CONFIG_SCREEN_LAYOUT = 0x0800; 898 /** @hide Native-specific bit mask for UI_MODE config; DO NOT USE UNLESS YOU ARE SURE. */ 899 public static final int NATIVE_CONFIG_UI_MODE = 0x1000; 900 /** @hide Native-specific bit mask for SMALLEST_SCREEN_SIZE config; DO NOT USE UNLESS YOU 901 * ARE SURE. */ 902 public static final int NATIVE_CONFIG_SMALLEST_SCREEN_SIZE = 0x2000; 903 /** @hide Native-specific bit mask for LAYOUTDIR config ; DO NOT USE UNLESS YOU ARE SURE.*/ 904 public static final int NATIVE_CONFIG_LAYOUTDIR = 0x4000; 905 /** @hide Native-specific bit mask for COLOR_MODE config ; DO NOT USE UNLESS YOU ARE SURE.*/ 906 public static final int NATIVE_CONFIG_COLOR_MODE = 0x10000; 907 908 /** 909 * <p>Construct an invalid Configuration. This state is only suitable for constructing a 910 * Configuration delta that will be applied to some valid Configuration object. In order to 911 * create a valid standalone Configuration, you must call {@link #setToDefaults}. </p> 912 * 913 * <p>Example:</p> 914 * <pre class="prettyprint"> 915 * Configuration validConfig = new Configuration(); 916 * validConfig.setToDefaults(); 917 * 918 * Configuration deltaOnlyConfig = new Configuration(); 919 * deltaOnlyConfig.orientation = Configuration.ORIENTATION_LANDSCAPE; 920 * 921 * validConfig.updateFrom(deltaOnlyConfig); 922 * </pre> 923 */ Configuration()924 public Configuration() { 925 unset(); 926 } 927 928 /** 929 * Makes a deep copy suitable for modification. 930 */ Configuration(Configuration o)931 public Configuration(Configuration o) { 932 setTo(o); 933 } 934 935 /* This brings mLocaleList in sync with locale in case a user of the older API who doesn't know 936 * about setLocales() has changed locale directly. */ fixUpLocaleList()937 private void fixUpLocaleList() { 938 if ((locale == null && !mLocaleList.isEmpty()) || 939 (locale != null && !locale.equals(mLocaleList.get(0)))) { 940 mLocaleList = locale == null ? LocaleList.getEmptyLocaleList() : new LocaleList(locale); 941 } 942 } 943 944 /** 945 * Sets the fields in this object to those in the given Configuration. 946 * 947 * @param o The Configuration object used to set the values of this Configuration's fields. 948 */ setTo(Configuration o)949 public void setTo(Configuration o) { 950 fontScale = o.fontScale; 951 mcc = o.mcc; 952 mnc = o.mnc; 953 if (o.locale == null) { 954 locale = null; 955 } else if (!o.locale.equals(locale)) { 956 // Only clone a new Locale instance if we need to: the clone() is 957 // both CPU and GC intensive. 958 locale = (Locale) o.locale.clone(); 959 } 960 o.fixUpLocaleList(); 961 mLocaleList = o.mLocaleList; 962 userSetLocale = o.userSetLocale; 963 touchscreen = o.touchscreen; 964 keyboard = o.keyboard; 965 keyboardHidden = o.keyboardHidden; 966 hardKeyboardHidden = o.hardKeyboardHidden; 967 navigation = o.navigation; 968 navigationHidden = o.navigationHidden; 969 orientation = o.orientation; 970 screenLayout = o.screenLayout; 971 colorMode = o.colorMode; 972 uiMode = o.uiMode; 973 screenWidthDp = o.screenWidthDp; 974 screenHeightDp = o.screenHeightDp; 975 smallestScreenWidthDp = o.smallestScreenWidthDp; 976 densityDpi = o.densityDpi; 977 compatScreenWidthDp = o.compatScreenWidthDp; 978 compatScreenHeightDp = o.compatScreenHeightDp; 979 compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp; 980 assetsSeq = o.assetsSeq; 981 seq = o.seq; 982 windowConfiguration.setTo(o.windowConfiguration); 983 fontWeightAdjustment = o.fontWeightAdjustment; 984 } 985 toString()986 public String toString() { 987 StringBuilder sb = new StringBuilder(128); 988 sb.append("{"); 989 sb.append(fontScale); 990 sb.append(" "); 991 if (mcc != 0) { 992 sb.append(mcc); 993 sb.append("mcc"); 994 } else { 995 sb.append("?mcc"); 996 } 997 if (mnc != 0) { 998 sb.append(mnc); 999 sb.append("mnc"); 1000 } else { 1001 sb.append("?mnc"); 1002 } 1003 fixUpLocaleList(); 1004 if (!mLocaleList.isEmpty()) { 1005 sb.append(" "); 1006 sb.append(mLocaleList); 1007 } else { 1008 sb.append(" ?localeList"); 1009 } 1010 int layoutDir = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK); 1011 switch (layoutDir) { 1012 case SCREENLAYOUT_LAYOUTDIR_UNDEFINED: sb.append(" ?layoutDir"); break; 1013 case SCREENLAYOUT_LAYOUTDIR_LTR: sb.append(" ldltr"); break; 1014 case SCREENLAYOUT_LAYOUTDIR_RTL: sb.append(" ldrtl"); break; 1015 default: sb.append(" layoutDir="); 1016 sb.append(layoutDir >> SCREENLAYOUT_LAYOUTDIR_SHIFT); break; 1017 } 1018 if (smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { 1019 sb.append(" sw"); sb.append(smallestScreenWidthDp); sb.append("dp"); 1020 } else { 1021 sb.append(" ?swdp"); 1022 } 1023 if (screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) { 1024 sb.append(" w"); sb.append(screenWidthDp); sb.append("dp"); 1025 } else { 1026 sb.append(" ?wdp"); 1027 } 1028 if (screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) { 1029 sb.append(" h"); sb.append(screenHeightDp); sb.append("dp"); 1030 } else { 1031 sb.append(" ?hdp"); 1032 } 1033 if (densityDpi != DENSITY_DPI_UNDEFINED) { 1034 sb.append(" "); sb.append(densityDpi); sb.append("dpi"); 1035 } else { 1036 sb.append(" ?density"); 1037 } 1038 switch ((screenLayout&SCREENLAYOUT_SIZE_MASK)) { 1039 case SCREENLAYOUT_SIZE_UNDEFINED: sb.append(" ?lsize"); break; 1040 case SCREENLAYOUT_SIZE_SMALL: sb.append(" smll"); break; 1041 case SCREENLAYOUT_SIZE_NORMAL: sb.append(" nrml"); break; 1042 case SCREENLAYOUT_SIZE_LARGE: sb.append(" lrg"); break; 1043 case SCREENLAYOUT_SIZE_XLARGE: sb.append(" xlrg"); break; 1044 default: sb.append(" layoutSize="); 1045 sb.append(screenLayout&SCREENLAYOUT_SIZE_MASK); break; 1046 } 1047 switch ((screenLayout&SCREENLAYOUT_LONG_MASK)) { 1048 case SCREENLAYOUT_LONG_UNDEFINED: sb.append(" ?long"); break; 1049 case SCREENLAYOUT_LONG_NO: /* not-long is not interesting to print */ break; 1050 case SCREENLAYOUT_LONG_YES: sb.append(" long"); break; 1051 default: sb.append(" layoutLong="); 1052 sb.append(screenLayout&SCREENLAYOUT_LONG_MASK); break; 1053 } 1054 switch ((colorMode &COLOR_MODE_HDR_MASK)) { 1055 case COLOR_MODE_HDR_UNDEFINED: sb.append(" ?ldr"); break; // most likely not HDR 1056 case COLOR_MODE_HDR_NO: /* ldr is not interesting to print */ break; 1057 case COLOR_MODE_HDR_YES: sb.append(" hdr"); break; 1058 default: sb.append(" dynamicRange="); 1059 sb.append(colorMode &COLOR_MODE_HDR_MASK); break; 1060 } 1061 switch ((colorMode &COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) { 1062 case COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED: sb.append(" ?wideColorGamut"); break; 1063 case COLOR_MODE_WIDE_COLOR_GAMUT_NO: /* not wide is not interesting to print */ break; 1064 case COLOR_MODE_WIDE_COLOR_GAMUT_YES: sb.append(" widecg"); break; 1065 default: sb.append(" wideColorGamut="); 1066 sb.append(colorMode &COLOR_MODE_WIDE_COLOR_GAMUT_MASK); break; 1067 } 1068 switch (orientation) { 1069 case ORIENTATION_UNDEFINED: sb.append(" ?orien"); break; 1070 case ORIENTATION_LANDSCAPE: sb.append(" land"); break; 1071 case ORIENTATION_PORTRAIT: sb.append(" port"); break; 1072 default: sb.append(" orien="); sb.append(orientation); break; 1073 } 1074 switch ((uiMode&UI_MODE_TYPE_MASK)) { 1075 case UI_MODE_TYPE_UNDEFINED: sb.append(" ?uimode"); break; 1076 case UI_MODE_TYPE_NORMAL: /* normal is not interesting to print */ break; 1077 case UI_MODE_TYPE_DESK: sb.append(" desk"); break; 1078 case UI_MODE_TYPE_CAR: sb.append(" car"); break; 1079 case UI_MODE_TYPE_TELEVISION: sb.append(" television"); break; 1080 case UI_MODE_TYPE_APPLIANCE: sb.append(" appliance"); break; 1081 case UI_MODE_TYPE_WATCH: sb.append(" watch"); break; 1082 case UI_MODE_TYPE_VR_HEADSET: sb.append(" vrheadset"); break; 1083 default: sb.append(" uimode="); sb.append(uiMode&UI_MODE_TYPE_MASK); break; 1084 } 1085 switch ((uiMode&UI_MODE_NIGHT_MASK)) { 1086 case UI_MODE_NIGHT_UNDEFINED: sb.append(" ?night"); break; 1087 case UI_MODE_NIGHT_NO: /* not-night is not interesting to print */ break; 1088 case UI_MODE_NIGHT_YES: sb.append(" night"); break; 1089 default: sb.append(" night="); sb.append(uiMode&UI_MODE_NIGHT_MASK); break; 1090 } 1091 switch (touchscreen) { 1092 case TOUCHSCREEN_UNDEFINED: sb.append(" ?touch"); break; 1093 case TOUCHSCREEN_NOTOUCH: sb.append(" -touch"); break; 1094 case TOUCHSCREEN_STYLUS: sb.append(" stylus"); break; 1095 case TOUCHSCREEN_FINGER: sb.append(" finger"); break; 1096 default: sb.append(" touch="); sb.append(touchscreen); break; 1097 } 1098 switch (keyboard) { 1099 case KEYBOARD_UNDEFINED: sb.append(" ?keyb"); break; 1100 case KEYBOARD_NOKEYS: sb.append(" -keyb"); break; 1101 case KEYBOARD_QWERTY: sb.append(" qwerty"); break; 1102 case KEYBOARD_12KEY: sb.append(" 12key"); break; 1103 default: sb.append(" keys="); sb.append(keyboard); break; 1104 } 1105 switch (keyboardHidden) { 1106 case KEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break; 1107 case KEYBOARDHIDDEN_NO: sb.append("/v"); break; 1108 case KEYBOARDHIDDEN_YES: sb.append("/h"); break; 1109 case KEYBOARDHIDDEN_SOFT: sb.append("/s"); break; 1110 default: sb.append("/"); sb.append(keyboardHidden); break; 1111 } 1112 switch (hardKeyboardHidden) { 1113 case HARDKEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break; 1114 case HARDKEYBOARDHIDDEN_NO: sb.append("/v"); break; 1115 case HARDKEYBOARDHIDDEN_YES: sb.append("/h"); break; 1116 default: sb.append("/"); sb.append(hardKeyboardHidden); break; 1117 } 1118 switch (navigation) { 1119 case NAVIGATION_UNDEFINED: sb.append(" ?nav"); break; 1120 case NAVIGATION_NONAV: sb.append(" -nav"); break; 1121 case NAVIGATION_DPAD: sb.append(" dpad"); break; 1122 case NAVIGATION_TRACKBALL: sb.append(" tball"); break; 1123 case NAVIGATION_WHEEL: sb.append(" wheel"); break; 1124 default: sb.append(" nav="); sb.append(navigation); break; 1125 } 1126 switch (navigationHidden) { 1127 case NAVIGATIONHIDDEN_UNDEFINED: sb.append("/?"); break; 1128 case NAVIGATIONHIDDEN_NO: sb.append("/v"); break; 1129 case NAVIGATIONHIDDEN_YES: sb.append("/h"); break; 1130 default: sb.append("/"); sb.append(navigationHidden); break; 1131 } 1132 sb.append(" winConfig="); sb.append(windowConfiguration); 1133 if (assetsSeq != 0) { 1134 sb.append(" as.").append(assetsSeq); 1135 } 1136 if (seq != 0) { 1137 sb.append(" s.").append(seq); 1138 } 1139 if (fontWeightAdjustment != FONT_WEIGHT_ADJUSTMENT_UNDEFINED) { 1140 sb.append(" fontWeightAdjustment="); 1141 sb.append(fontWeightAdjustment); 1142 } else { 1143 sb.append(" ?fontWeightAdjustment"); 1144 } 1145 sb.append('}'); 1146 return sb.toString(); 1147 } 1148 1149 /** 1150 * Write to a protocol buffer output stream. 1151 * Protocol buffer message definition at {@link android.content.ConfigurationProto} 1152 * Has the option to ignore fields that don't need to be persisted to disk. 1153 * 1154 * @param protoOutputStream Stream to write the Configuration object to. 1155 * @param fieldId Field Id of the Configuration as defined in the parent message 1156 * @param persisted Note if this proto will be persisted to disk 1157 * @param critical If true, reduce amount of data written. 1158 * @hide 1159 */ dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean persisted, boolean critical)1160 public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean persisted, 1161 boolean critical) { 1162 final long token = protoOutputStream.start(fieldId); 1163 if (!critical) { 1164 protoOutputStream.write(FONT_SCALE, fontScale); 1165 protoOutputStream.write(MCC, mcc); 1166 protoOutputStream.write(MNC, mnc); 1167 if (mLocaleList != null) { 1168 protoOutputStream.write(LOCALE_LIST, mLocaleList.toLanguageTags()); 1169 } 1170 protoOutputStream.write(SCREEN_LAYOUT, screenLayout); 1171 protoOutputStream.write(COLOR_MODE, colorMode); 1172 protoOutputStream.write(TOUCHSCREEN, touchscreen); 1173 protoOutputStream.write(KEYBOARD, keyboard); 1174 protoOutputStream.write(KEYBOARD_HIDDEN, keyboardHidden); 1175 protoOutputStream.write(HARD_KEYBOARD_HIDDEN, hardKeyboardHidden); 1176 protoOutputStream.write(NAVIGATION, navigation); 1177 protoOutputStream.write(NAVIGATION_HIDDEN, navigationHidden); 1178 protoOutputStream.write(UI_MODE, uiMode); 1179 protoOutputStream.write(SMALLEST_SCREEN_WIDTH_DP, smallestScreenWidthDp); 1180 protoOutputStream.write(DENSITY_DPI, densityDpi); 1181 // For persistence, we do not care about window configuration 1182 if (!persisted && windowConfiguration != null) { 1183 windowConfiguration.dumpDebug(protoOutputStream, WINDOW_CONFIGURATION); 1184 } 1185 protoOutputStream.write(FONT_WEIGHT_ADJUSTMENT, fontWeightAdjustment); 1186 } 1187 protoOutputStream.write(ORIENTATION, orientation); 1188 protoOutputStream.write(SCREEN_WIDTH_DP, screenWidthDp); 1189 protoOutputStream.write(SCREEN_HEIGHT_DP, screenHeightDp); 1190 protoOutputStream.end(token); 1191 } 1192 1193 /** 1194 * Write to a protocol buffer output stream. 1195 * Protocol buffer message definition at {@link android.content.ConfigurationProto} 1196 * 1197 * @param protoOutputStream Stream to write the Configuration object to. 1198 * @param fieldId Field Id of the Configuration as defined in the parent message 1199 * @hide 1200 */ dumpDebug(ProtoOutputStream protoOutputStream, long fieldId)1201 public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId) { 1202 dumpDebug(protoOutputStream, fieldId, false /* persisted */, false /* critical */); 1203 } 1204 1205 /** 1206 * Write to a protocol buffer output stream. 1207 * Protocol buffer message definition at {@link android.content.ConfigurationProto} 1208 * 1209 * @param protoOutputStream Stream to write the Configuration object to. 1210 * @param fieldId Field Id of the Configuration as defined in the parent message 1211 * @param critical If true, reduce amount of data written. 1212 * @hide 1213 */ dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean critical)1214 public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean critical) { 1215 dumpDebug(protoOutputStream, fieldId, false /* persisted */, critical); 1216 } 1217 1218 /** 1219 * Read from a protocol buffer output stream. 1220 * Protocol buffer message definition at {@link android.content.ConfigurationProto} 1221 * 1222 * @param protoInputStream Stream to read the Configuration object from. 1223 * @param fieldId Field Id of the Configuration as defined in the parent message 1224 * @hide 1225 */ readFromProto(ProtoInputStream protoInputStream, long fieldId)1226 public void readFromProto(ProtoInputStream protoInputStream, long fieldId) throws IOException { 1227 final long token = protoInputStream.start(fieldId); 1228 final List<Locale> list = new ArrayList(); 1229 try { 1230 while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { 1231 switch (protoInputStream.getFieldNumber()) { 1232 case (int) FONT_SCALE: 1233 fontScale = protoInputStream.readFloat(FONT_SCALE); 1234 break; 1235 case (int) MCC: 1236 mcc = protoInputStream.readInt(MCC); 1237 break; 1238 case (int) MNC: 1239 mnc = protoInputStream.readInt(MNC); 1240 break; 1241 case (int) LOCALES: 1242 // Parse the Locale here to handle all the repeated Locales 1243 // The LocaleList will be created when the message is completed 1244 final long localeToken = protoInputStream.start(LOCALES); 1245 String language = ""; 1246 String country = ""; 1247 String variant = ""; 1248 String script = ""; 1249 try { 1250 while (protoInputStream.nextField() 1251 != ProtoInputStream.NO_MORE_FIELDS) { 1252 switch (protoInputStream.getFieldNumber()) { 1253 case (int) LocaleProto.LANGUAGE: 1254 language = protoInputStream.readString( 1255 LocaleProto.LANGUAGE); 1256 break; 1257 case (int) LocaleProto.COUNTRY: 1258 country = protoInputStream.readString(LocaleProto.COUNTRY); 1259 break; 1260 case (int) LocaleProto.VARIANT: 1261 variant = protoInputStream.readString(LocaleProto.VARIANT); 1262 break; 1263 case (int) LocaleProto.SCRIPT: 1264 script = protoInputStream.readString(LocaleProto.SCRIPT); 1265 break; 1266 } 1267 } 1268 } catch (WireTypeMismatchException wtme) { 1269 // rethrow for caller deal with 1270 throw wtme; 1271 } finally { 1272 protoInputStream.end(localeToken); 1273 try { 1274 final Locale locale = new Locale.Builder() 1275 .setLanguage(language) 1276 .setRegion(country) 1277 .setVariant(variant) 1278 .setScript(script) 1279 .build(); 1280 // Log a WTF here if a repeated locale is found to avoid throwing an 1281 // exception in system server when LocaleList is created below 1282 final int inListIndex = list.indexOf(locale); 1283 if (inListIndex != -1) { 1284 Slog.wtf(TAG, "Repeated locale (" + list.get(inListIndex) + ")" 1285 + " found when trying to add: " + locale.toString()); 1286 } else { 1287 list.add(locale); 1288 } 1289 } catch (IllformedLocaleException e) { 1290 Slog.e(TAG, "readFromProto error building locale with: " 1291 + "language-" + language + ";country-" + country 1292 + ";variant-" + variant + ";script-" + script); 1293 } 1294 } 1295 break; 1296 case (int) SCREEN_LAYOUT: 1297 screenLayout = protoInputStream.readInt(SCREEN_LAYOUT); 1298 break; 1299 case (int) COLOR_MODE: 1300 colorMode = protoInputStream.readInt(COLOR_MODE); 1301 break; 1302 case (int) TOUCHSCREEN: 1303 touchscreen = protoInputStream.readInt(TOUCHSCREEN); 1304 break; 1305 case (int) KEYBOARD: 1306 keyboard = protoInputStream.readInt(KEYBOARD); 1307 break; 1308 case (int) KEYBOARD_HIDDEN: 1309 keyboardHidden = protoInputStream.readInt(KEYBOARD_HIDDEN); 1310 break; 1311 case (int) HARD_KEYBOARD_HIDDEN: 1312 hardKeyboardHidden = protoInputStream.readInt(HARD_KEYBOARD_HIDDEN); 1313 break; 1314 case (int) NAVIGATION: 1315 navigation = protoInputStream.readInt(NAVIGATION); 1316 break; 1317 case (int) NAVIGATION_HIDDEN: 1318 navigationHidden = protoInputStream.readInt(NAVIGATION_HIDDEN); 1319 break; 1320 case (int) ORIENTATION: 1321 orientation = protoInputStream.readInt(ORIENTATION); 1322 break; 1323 case (int) UI_MODE: 1324 uiMode = protoInputStream.readInt(UI_MODE); 1325 break; 1326 case (int) SCREEN_WIDTH_DP: 1327 screenWidthDp = protoInputStream.readInt(SCREEN_WIDTH_DP); 1328 break; 1329 case (int) SCREEN_HEIGHT_DP: 1330 screenHeightDp = protoInputStream.readInt(SCREEN_HEIGHT_DP); 1331 break; 1332 case (int) SMALLEST_SCREEN_WIDTH_DP: 1333 smallestScreenWidthDp = protoInputStream.readInt(SMALLEST_SCREEN_WIDTH_DP); 1334 break; 1335 case (int) DENSITY_DPI: 1336 densityDpi = protoInputStream.readInt(DENSITY_DPI); 1337 break; 1338 case (int) WINDOW_CONFIGURATION: 1339 windowConfiguration.readFromProto(protoInputStream, WINDOW_CONFIGURATION); 1340 break; 1341 case (int) LOCALE_LIST: 1342 try { 1343 setLocales(LocaleList.forLanguageTags(protoInputStream.readString( 1344 LOCALE_LIST))); 1345 } catch (Exception e) { 1346 Slog.e(TAG, "error parsing locale list in configuration.", e); 1347 } 1348 break; 1349 case (int) FONT_WEIGHT_ADJUSTMENT: 1350 fontWeightAdjustment = protoInputStream.readInt(FONT_WEIGHT_ADJUSTMENT); 1351 break; 1352 } 1353 } 1354 } finally { 1355 // Let caller handle any exceptions 1356 if (list.size() > 0) { 1357 //Create the LocaleList from the collected Locales 1358 setLocales(new LocaleList(list.toArray(new Locale[list.size()]))); 1359 } 1360 protoInputStream.end(token); 1361 } 1362 } 1363 1364 /** 1365 * Write full {@link android.content.ResourcesConfigurationProto} to protocol buffer output 1366 * stream. 1367 * 1368 * @param protoOutputStream Stream to write the Configuration object to. 1369 * @param fieldId Field Id of the Configuration as defined in the parent message 1370 * @param metrics Current display information 1371 * @hide 1372 */ writeResConfigToProto(ProtoOutputStream protoOutputStream, long fieldId, DisplayMetrics metrics)1373 public void writeResConfigToProto(ProtoOutputStream protoOutputStream, long fieldId, 1374 DisplayMetrics metrics) { 1375 final int width, height; 1376 if (metrics.widthPixels >= metrics.heightPixels) { 1377 width = metrics.widthPixels; 1378 height = metrics.heightPixels; 1379 } else { 1380 //noinspection SuspiciousNameCombination 1381 width = metrics.heightPixels; 1382 //noinspection SuspiciousNameCombination 1383 height = metrics.widthPixels; 1384 } 1385 1386 final long token = protoOutputStream.start(fieldId); 1387 dumpDebug(protoOutputStream, CONFIGURATION); 1388 protoOutputStream.write(SDK_VERSION, Build.VERSION.RESOURCES_SDK_INT); 1389 protoOutputStream.write(SCREEN_WIDTH_PX, width); 1390 protoOutputStream.write(SCREEN_HEIGHT_PX, height); 1391 protoOutputStream.end(token); 1392 } 1393 1394 /** 1395 * Convert the UI mode to a human readable format. 1396 * @hide 1397 */ uiModeToString(int uiMode)1398 public static String uiModeToString(int uiMode) { 1399 switch (uiMode) { 1400 case UI_MODE_TYPE_UNDEFINED: 1401 return "UI_MODE_TYPE_UNDEFINED"; 1402 case UI_MODE_TYPE_NORMAL: 1403 return "UI_MODE_TYPE_NORMAL"; 1404 case UI_MODE_TYPE_DESK: 1405 return "UI_MODE_TYPE_DESK"; 1406 case UI_MODE_TYPE_CAR: 1407 return "UI_MODE_TYPE_CAR"; 1408 case UI_MODE_TYPE_TELEVISION: 1409 return "UI_MODE_TYPE_TELEVISION"; 1410 case UI_MODE_TYPE_APPLIANCE: 1411 return "UI_MODE_TYPE_APPLIANCE"; 1412 case UI_MODE_TYPE_WATCH: 1413 return "UI_MODE_TYPE_WATCH"; 1414 case UI_MODE_TYPE_VR_HEADSET: 1415 return "UI_MODE_TYPE_VR_HEADSET"; 1416 default: 1417 return Integer.toString(uiMode); 1418 } 1419 } 1420 1421 /** 1422 * Set this object to the system defaults. 1423 */ setToDefaults()1424 public void setToDefaults() { 1425 fontScale = 1; 1426 mcc = mnc = 0; 1427 mLocaleList = LocaleList.getEmptyLocaleList(); 1428 locale = null; 1429 userSetLocale = false; 1430 touchscreen = TOUCHSCREEN_UNDEFINED; 1431 keyboard = KEYBOARD_UNDEFINED; 1432 keyboardHidden = KEYBOARDHIDDEN_UNDEFINED; 1433 hardKeyboardHidden = HARDKEYBOARDHIDDEN_UNDEFINED; 1434 navigation = NAVIGATION_UNDEFINED; 1435 navigationHidden = NAVIGATIONHIDDEN_UNDEFINED; 1436 orientation = ORIENTATION_UNDEFINED; 1437 screenLayout = SCREENLAYOUT_UNDEFINED; 1438 colorMode = COLOR_MODE_UNDEFINED; 1439 uiMode = UI_MODE_TYPE_UNDEFINED; 1440 screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED; 1441 screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED; 1442 smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; 1443 densityDpi = DENSITY_DPI_UNDEFINED; 1444 assetsSeq = ASSETS_SEQ_UNDEFINED; 1445 seq = 0; 1446 windowConfiguration.setToDefaults(); 1447 fontWeightAdjustment = FONT_WEIGHT_ADJUSTMENT_UNDEFINED; 1448 } 1449 1450 /** 1451 * Set this object to completely undefined. 1452 * @hide 1453 */ unset()1454 public void unset() { 1455 setToDefaults(); 1456 fontScale = 0; 1457 } 1458 1459 /** {@hide} */ 1460 @UnsupportedAppUsage makeDefault()1461 @Deprecated public void makeDefault() { 1462 setToDefaults(); 1463 } 1464 1465 /** 1466 * Copies the fields from delta into this Configuration object, keeping 1467 * track of which ones have changed. Any undefined fields in {@code delta} 1468 * are ignored and not copied in to the current Configuration. 1469 * 1470 * @return a bit mask of the changed fields, as per {@link #diff} 1471 */ updateFrom(@onNull Configuration delta)1472 public @Config int updateFrom(@NonNull Configuration delta) { 1473 int changed = 0; 1474 if (delta.fontScale > 0 && fontScale != delta.fontScale) { 1475 changed |= ActivityInfo.CONFIG_FONT_SCALE; 1476 fontScale = delta.fontScale; 1477 } 1478 if (delta.mcc != 0 && mcc != delta.mcc) { 1479 changed |= ActivityInfo.CONFIG_MCC; 1480 mcc = delta.mcc; 1481 } 1482 if (delta.mnc != 0 && mnc != delta.mnc) { 1483 changed |= ActivityInfo.CONFIG_MNC; 1484 mnc = delta.mnc; 1485 } 1486 fixUpLocaleList(); 1487 delta.fixUpLocaleList(); 1488 if (!delta.mLocaleList.isEmpty() && !mLocaleList.equals(delta.mLocaleList)) { 1489 changed |= ActivityInfo.CONFIG_LOCALE; 1490 mLocaleList = delta.mLocaleList; 1491 // delta.locale can't be null, since delta.mLocaleList is not empty. 1492 if (!delta.locale.equals(locale)) { 1493 locale = (Locale) delta.locale.clone(); 1494 // If locale has changed, then layout direction is also changed ... 1495 changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; 1496 // ... and we need to update the layout direction (represented by the first 1497 // 2 most significant bits in screenLayout). 1498 setLayoutDirection(locale); 1499 } 1500 } 1501 final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK; 1502 if (deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED && 1503 deltaScreenLayoutDir != (screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) { 1504 screenLayout = (screenLayout & ~SCREENLAYOUT_LAYOUTDIR_MASK) | deltaScreenLayoutDir; 1505 changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; 1506 } 1507 if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0))) 1508 { 1509 changed |= ActivityInfo.CONFIG_LOCALE; 1510 userSetLocale = true; 1511 } 1512 if (delta.touchscreen != TOUCHSCREEN_UNDEFINED 1513 && touchscreen != delta.touchscreen) { 1514 changed |= ActivityInfo.CONFIG_TOUCHSCREEN; 1515 touchscreen = delta.touchscreen; 1516 } 1517 if (delta.keyboard != KEYBOARD_UNDEFINED 1518 && keyboard != delta.keyboard) { 1519 changed |= ActivityInfo.CONFIG_KEYBOARD; 1520 keyboard = delta.keyboard; 1521 } 1522 if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED 1523 && keyboardHidden != delta.keyboardHidden) { 1524 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 1525 keyboardHidden = delta.keyboardHidden; 1526 } 1527 if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED 1528 && hardKeyboardHidden != delta.hardKeyboardHidden) { 1529 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 1530 hardKeyboardHidden = delta.hardKeyboardHidden; 1531 } 1532 if (delta.navigation != NAVIGATION_UNDEFINED 1533 && navigation != delta.navigation) { 1534 changed |= ActivityInfo.CONFIG_NAVIGATION; 1535 navigation = delta.navigation; 1536 } 1537 if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED 1538 && navigationHidden != delta.navigationHidden) { 1539 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 1540 navigationHidden = delta.navigationHidden; 1541 } 1542 if (delta.orientation != ORIENTATION_UNDEFINED 1543 && orientation != delta.orientation) { 1544 changed |= ActivityInfo.CONFIG_ORIENTATION; 1545 orientation = delta.orientation; 1546 } 1547 if (((delta.screenLayout & SCREENLAYOUT_SIZE_MASK) != SCREENLAYOUT_SIZE_UNDEFINED) 1548 && (delta.screenLayout & SCREENLAYOUT_SIZE_MASK) 1549 != (screenLayout & SCREENLAYOUT_SIZE_MASK)) { 1550 changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; 1551 screenLayout = (screenLayout & ~SCREENLAYOUT_SIZE_MASK) 1552 | (delta.screenLayout & SCREENLAYOUT_SIZE_MASK); 1553 } 1554 if (((delta.screenLayout & SCREENLAYOUT_LONG_MASK) != SCREENLAYOUT_LONG_UNDEFINED) 1555 && (delta.screenLayout & SCREENLAYOUT_LONG_MASK) 1556 != (screenLayout & SCREENLAYOUT_LONG_MASK)) { 1557 changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; 1558 screenLayout = (screenLayout & ~SCREENLAYOUT_LONG_MASK) 1559 | (delta.screenLayout & SCREENLAYOUT_LONG_MASK); 1560 } 1561 if (((delta.screenLayout & SCREENLAYOUT_ROUND_MASK) != SCREENLAYOUT_ROUND_UNDEFINED) 1562 && (delta.screenLayout & SCREENLAYOUT_ROUND_MASK) 1563 != (screenLayout & SCREENLAYOUT_ROUND_MASK)) { 1564 changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; 1565 screenLayout = (screenLayout & ~SCREENLAYOUT_ROUND_MASK) 1566 | (delta.screenLayout & SCREENLAYOUT_ROUND_MASK); 1567 } 1568 if ((delta.screenLayout & SCREENLAYOUT_COMPAT_NEEDED) 1569 != (screenLayout & SCREENLAYOUT_COMPAT_NEEDED) 1570 && delta.screenLayout != 0) { 1571 changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; 1572 screenLayout = (screenLayout & ~SCREENLAYOUT_COMPAT_NEEDED) 1573 | (delta.screenLayout & SCREENLAYOUT_COMPAT_NEEDED); 1574 } 1575 1576 if (((delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) != 1577 COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED) 1578 && (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) 1579 != (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) { 1580 changed |= ActivityInfo.CONFIG_COLOR_MODE; 1581 colorMode = (colorMode & ~COLOR_MODE_WIDE_COLOR_GAMUT_MASK) 1582 | (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK); 1583 } 1584 1585 if (((delta.colorMode & COLOR_MODE_HDR_MASK) != COLOR_MODE_HDR_UNDEFINED) 1586 && (delta.colorMode & COLOR_MODE_HDR_MASK) 1587 != (colorMode & COLOR_MODE_HDR_MASK)) { 1588 changed |= ActivityInfo.CONFIG_COLOR_MODE; 1589 colorMode = (colorMode & ~COLOR_MODE_HDR_MASK) 1590 | (delta.colorMode & COLOR_MODE_HDR_MASK); 1591 } 1592 1593 if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED) 1594 && uiMode != delta.uiMode) { 1595 changed |= ActivityInfo.CONFIG_UI_MODE; 1596 if ((delta.uiMode&UI_MODE_TYPE_MASK) != UI_MODE_TYPE_UNDEFINED) { 1597 uiMode = (uiMode&~UI_MODE_TYPE_MASK) 1598 | (delta.uiMode&UI_MODE_TYPE_MASK); 1599 } 1600 if ((delta.uiMode&UI_MODE_NIGHT_MASK) != UI_MODE_NIGHT_UNDEFINED) { 1601 uiMode = (uiMode&~UI_MODE_NIGHT_MASK) 1602 | (delta.uiMode&UI_MODE_NIGHT_MASK); 1603 } 1604 } 1605 if (delta.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED 1606 && screenWidthDp != delta.screenWidthDp) { 1607 changed |= ActivityInfo.CONFIG_SCREEN_SIZE; 1608 screenWidthDp = delta.screenWidthDp; 1609 } 1610 if (delta.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED 1611 && screenHeightDp != delta.screenHeightDp) { 1612 changed |= ActivityInfo.CONFIG_SCREEN_SIZE; 1613 screenHeightDp = delta.screenHeightDp; 1614 } 1615 if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED 1616 && smallestScreenWidthDp != delta.smallestScreenWidthDp) { 1617 changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; 1618 smallestScreenWidthDp = delta.smallestScreenWidthDp; 1619 } 1620 if (delta.densityDpi != DENSITY_DPI_UNDEFINED && 1621 densityDpi != delta.densityDpi) { 1622 changed |= ActivityInfo.CONFIG_DENSITY; 1623 densityDpi = delta.densityDpi; 1624 } 1625 if (delta.compatScreenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) { 1626 compatScreenWidthDp = delta.compatScreenWidthDp; 1627 } 1628 if (delta.compatScreenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) { 1629 compatScreenHeightDp = delta.compatScreenHeightDp; 1630 } 1631 if (delta.compatSmallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { 1632 compatSmallestScreenWidthDp = delta.compatSmallestScreenWidthDp; 1633 } 1634 if (delta.assetsSeq != ASSETS_SEQ_UNDEFINED && delta.assetsSeq != assetsSeq) { 1635 changed |= ActivityInfo.CONFIG_ASSETS_PATHS; 1636 assetsSeq = delta.assetsSeq; 1637 } 1638 if (delta.seq != 0) { 1639 seq = delta.seq; 1640 } 1641 if (windowConfiguration.updateFrom(delta.windowConfiguration) != 0) { 1642 changed |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION; 1643 } 1644 1645 if (delta.fontWeightAdjustment != FONT_WEIGHT_ADJUSTMENT_UNDEFINED 1646 && delta.fontWeightAdjustment != fontWeightAdjustment) { 1647 changed |= ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT; 1648 fontWeightAdjustment = delta.fontWeightAdjustment; 1649 } 1650 1651 return changed; 1652 } 1653 1654 /** 1655 * Copies the fields specified by mask from delta into this Configuration object. This will 1656 * copy anything allowed by the mask (including undefined values). 1657 * @hide 1658 */ setTo(@onNull Configuration delta, @Config int mask, @WindowConfiguration.WindowConfig int windowMask)1659 public void setTo(@NonNull Configuration delta, @Config int mask, 1660 @WindowConfiguration.WindowConfig int windowMask) { 1661 if ((mask & ActivityInfo.CONFIG_FONT_SCALE) != 0) { 1662 fontScale = delta.fontScale; 1663 } 1664 if ((mask & ActivityInfo.CONFIG_MCC) != 0) { 1665 mcc = delta.mcc; 1666 } 1667 if ((mask & ActivityInfo.CONFIG_MNC) != 0) { 1668 mnc = delta.mnc; 1669 } 1670 if ((mask & ActivityInfo.CONFIG_LOCALE) != 0) { 1671 mLocaleList = delta.mLocaleList; 1672 if (!mLocaleList.isEmpty()) { 1673 if (!delta.locale.equals(locale)) { 1674 // Don't churn a new Locale clone unless we're actually changing it 1675 locale = (Locale) delta.locale.clone(); 1676 } 1677 } 1678 } 1679 if ((mask & ActivityInfo.CONFIG_LAYOUT_DIRECTION) != 0) { 1680 final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK; 1681 screenLayout = (screenLayout & ~SCREENLAYOUT_LAYOUTDIR_MASK) | deltaScreenLayoutDir; 1682 } 1683 if ((mask & ActivityInfo.CONFIG_LOCALE) != 0) { 1684 userSetLocale = delta.userSetLocale; 1685 } 1686 if ((mask & ActivityInfo.CONFIG_TOUCHSCREEN) != 0) { 1687 touchscreen = delta.touchscreen; 1688 } 1689 if ((mask & ActivityInfo.CONFIG_KEYBOARD) != 0) { 1690 keyboard = delta.keyboard; 1691 } 1692 if ((mask & ActivityInfo.CONFIG_KEYBOARD_HIDDEN) != 0) { 1693 keyboardHidden = delta.keyboardHidden; 1694 hardKeyboardHidden = delta.hardKeyboardHidden; 1695 navigationHidden = delta.navigationHidden; 1696 } 1697 if ((mask & ActivityInfo.CONFIG_NAVIGATION) != 0) { 1698 navigation = delta.navigation; 1699 } 1700 if ((mask & ActivityInfo.CONFIG_ORIENTATION) != 0) { 1701 orientation = delta.orientation; 1702 } 1703 if ((mask & ActivityInfo.CONFIG_SCREEN_LAYOUT) != 0) { 1704 // Not enough granularity for each component unfortunately. 1705 screenLayout = screenLayout | (delta.screenLayout & ~SCREENLAYOUT_LAYOUTDIR_MASK); 1706 } 1707 if ((mask & ActivityInfo.CONFIG_COLOR_MODE) != 0) { 1708 colorMode = delta.colorMode; 1709 } 1710 if ((mask & ActivityInfo.CONFIG_UI_MODE) != 0) { 1711 uiMode = delta.uiMode; 1712 } 1713 if ((mask & ActivityInfo.CONFIG_SCREEN_SIZE) != 0) { 1714 screenWidthDp = delta.screenWidthDp; 1715 screenHeightDp = delta.screenHeightDp; 1716 } 1717 if ((mask & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0) { 1718 smallestScreenWidthDp = delta.smallestScreenWidthDp; 1719 } 1720 if ((mask & ActivityInfo.CONFIG_DENSITY) != 0) { 1721 densityDpi = delta.densityDpi; 1722 } 1723 if ((mask & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) { 1724 assetsSeq = delta.assetsSeq; 1725 } 1726 if ((mask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0) { 1727 windowConfiguration.setTo(delta.windowConfiguration, windowMask); 1728 } 1729 if ((mask & ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT) != 0) { 1730 fontWeightAdjustment = delta.fontWeightAdjustment; 1731 } 1732 } 1733 1734 /** 1735 * Return a bit mask of the differences between this Configuration 1736 * object and the given one. Does not change the values of either. Any 1737 * undefined fields in <var>delta</var> are ignored. 1738 * @return Returns a bit mask indicating which configuration 1739 * values has changed, containing any combination of 1740 * {@link android.content.pm.ActivityInfo#CONFIG_FONT_SCALE 1741 * PackageManager.ActivityInfo.CONFIG_FONT_SCALE}, 1742 * {@link android.content.pm.ActivityInfo#CONFIG_MCC 1743 * PackageManager.ActivityInfo.CONFIG_MCC}, 1744 * {@link android.content.pm.ActivityInfo#CONFIG_MNC 1745 * PackageManager.ActivityInfo.CONFIG_MNC}, 1746 * {@link android.content.pm.ActivityInfo#CONFIG_LOCALE 1747 * PackageManager.ActivityInfo.CONFIG_LOCALE}, 1748 * {@link android.content.pm.ActivityInfo#CONFIG_TOUCHSCREEN 1749 * PackageManager.ActivityInfo.CONFIG_TOUCHSCREEN}, 1750 * {@link android.content.pm.ActivityInfo#CONFIG_KEYBOARD 1751 * PackageManager.ActivityInfo.CONFIG_KEYBOARD}, 1752 * {@link android.content.pm.ActivityInfo#CONFIG_NAVIGATION 1753 * PackageManager.ActivityInfo.CONFIG_NAVIGATION}, 1754 * {@link android.content.pm.ActivityInfo#CONFIG_ORIENTATION 1755 * PackageManager.ActivityInfo.CONFIG_ORIENTATION}, 1756 * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_LAYOUT 1757 * PackageManager.ActivityInfo.CONFIG_SCREEN_LAYOUT}, or 1758 * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_SIZE 1759 * PackageManager.ActivityInfo.CONFIG_SCREEN_SIZE}, or 1760 * {@link android.content.pm.ActivityInfo#CONFIG_SMALLEST_SCREEN_SIZE 1761 * PackageManager.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE}. 1762 * {@link android.content.pm.ActivityInfo#CONFIG_LAYOUT_DIRECTION 1763 * PackageManager.ActivityInfo.CONFIG_LAYOUT_DIRECTION}. 1764 * {@link android.content.pm.ActivityInfo#CONFIG_FONT_WEIGHT_ADJUSTMENT 1765 * PackageManager.ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT. 1766 */ diff(Configuration delta)1767 public int diff(Configuration delta) { 1768 return diff(delta, false /* compareUndefined */, false /* publicOnly */); 1769 } 1770 1771 /** 1772 * Returns the diff against the provided {@link Configuration} excluding values that would 1773 * publicly be equivalent, such as appBounds. 1774 * @param delta {@link Configuration} to compare to. 1775 * 1776 * TODO(b/36812336): Remove once appBounds has been moved out of Configuration. 1777 * {@hide} 1778 */ diffPublicOnly(Configuration delta)1779 public int diffPublicOnly(Configuration delta) { 1780 return diff(delta, false /* compareUndefined */, true /* publicOnly */); 1781 } 1782 1783 /** 1784 * Variation of {@link #diff(Configuration)} with an option to skip checks for undefined values. 1785 * 1786 * @hide 1787 */ diff(Configuration delta, boolean compareUndefined, boolean publicOnly)1788 public int diff(Configuration delta, boolean compareUndefined, boolean publicOnly) { 1789 int changed = 0; 1790 if ((compareUndefined || delta.fontScale > 0) && fontScale != delta.fontScale) { 1791 changed |= ActivityInfo.CONFIG_FONT_SCALE; 1792 } 1793 if ((compareUndefined || delta.mcc != 0) && mcc != delta.mcc) { 1794 changed |= ActivityInfo.CONFIG_MCC; 1795 } 1796 if ((compareUndefined || delta.mnc != 0) && mnc != delta.mnc) { 1797 changed |= ActivityInfo.CONFIG_MNC; 1798 } 1799 fixUpLocaleList(); 1800 delta.fixUpLocaleList(); 1801 if ((compareUndefined || !delta.mLocaleList.isEmpty()) 1802 && !mLocaleList.equals(delta.mLocaleList)) { 1803 changed |= ActivityInfo.CONFIG_LOCALE; 1804 changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; 1805 } 1806 final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK; 1807 if ((compareUndefined || deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED) 1808 && deltaScreenLayoutDir != (screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) { 1809 changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; 1810 } 1811 if ((compareUndefined || delta.touchscreen != TOUCHSCREEN_UNDEFINED) 1812 && touchscreen != delta.touchscreen) { 1813 changed |= ActivityInfo.CONFIG_TOUCHSCREEN; 1814 } 1815 if ((compareUndefined || delta.keyboard != KEYBOARD_UNDEFINED) 1816 && keyboard != delta.keyboard) { 1817 changed |= ActivityInfo.CONFIG_KEYBOARD; 1818 } 1819 if ((compareUndefined || delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED) 1820 && keyboardHidden != delta.keyboardHidden) { 1821 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 1822 } 1823 if ((compareUndefined || delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED) 1824 && hardKeyboardHidden != delta.hardKeyboardHidden) { 1825 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 1826 } 1827 if ((compareUndefined || delta.navigation != NAVIGATION_UNDEFINED) 1828 && navigation != delta.navigation) { 1829 changed |= ActivityInfo.CONFIG_NAVIGATION; 1830 } 1831 if ((compareUndefined || delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED) 1832 && navigationHidden != delta.navigationHidden) { 1833 changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; 1834 } 1835 if ((compareUndefined || delta.orientation != ORIENTATION_UNDEFINED) 1836 && orientation != delta.orientation) { 1837 changed |= ActivityInfo.CONFIG_ORIENTATION; 1838 } 1839 if ((compareUndefined || getScreenLayoutNoDirection(delta.screenLayout) != 1840 (SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED)) 1841 && getScreenLayoutNoDirection(screenLayout) != 1842 getScreenLayoutNoDirection(delta.screenLayout)) { 1843 changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; 1844 } 1845 if ((compareUndefined || 1846 (delta.colorMode & COLOR_MODE_HDR_MASK) != COLOR_MODE_HDR_UNDEFINED) 1847 && (colorMode & COLOR_MODE_HDR_MASK) != 1848 (delta.colorMode & COLOR_MODE_HDR_MASK)) { 1849 changed |= ActivityInfo.CONFIG_COLOR_MODE; 1850 } 1851 if ((compareUndefined || 1852 (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) != 1853 COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED) 1854 && (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) != 1855 (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) { 1856 changed |= ActivityInfo.CONFIG_COLOR_MODE; 1857 } 1858 if ((compareUndefined || delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED)) 1859 && uiMode != delta.uiMode) { 1860 changed |= ActivityInfo.CONFIG_UI_MODE; 1861 } 1862 if ((compareUndefined || delta.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) 1863 && screenWidthDp != delta.screenWidthDp) { 1864 changed |= ActivityInfo.CONFIG_SCREEN_SIZE; 1865 } 1866 if ((compareUndefined || delta.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) 1867 && screenHeightDp != delta.screenHeightDp) { 1868 changed |= ActivityInfo.CONFIG_SCREEN_SIZE; 1869 } 1870 if ((compareUndefined || delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) 1871 && smallestScreenWidthDp != delta.smallestScreenWidthDp) { 1872 changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; 1873 } 1874 if ((compareUndefined || delta.densityDpi != DENSITY_DPI_UNDEFINED) 1875 && densityDpi != delta.densityDpi) { 1876 changed |= ActivityInfo.CONFIG_DENSITY; 1877 } 1878 if ((compareUndefined || delta.assetsSeq != ASSETS_SEQ_UNDEFINED) 1879 && assetsSeq != delta.assetsSeq) { 1880 changed |= ActivityInfo.CONFIG_ASSETS_PATHS; 1881 } 1882 1883 // WindowConfiguration differences aren't considered public... 1884 if (!publicOnly 1885 && windowConfiguration.diff(delta.windowConfiguration, compareUndefined) != 0) { 1886 changed |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION; 1887 } 1888 1889 if ((compareUndefined || delta.fontWeightAdjustment != FONT_WEIGHT_ADJUSTMENT_UNDEFINED) 1890 && fontWeightAdjustment != delta.fontWeightAdjustment) { 1891 changed |= ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT; 1892 } 1893 return changed; 1894 } 1895 1896 /** 1897 * Determines if a new resource needs to be loaded from the bit set of 1898 * configuration changes returned by {@link #updateFrom(Configuration)}. 1899 * 1900 * @param configChanges the mask of changes configurations as returned by 1901 * {@link #updateFrom(Configuration)} 1902 * @param interestingChanges the configuration changes that the resource 1903 * can handle as given in 1904 * {@link android.util.TypedValue#changingConfigurations} 1905 * @return {@code true} if the resource needs to be loaded, {@code false} 1906 * otherwise 1907 */ needNewResources(@onfig int configChanges, @Config int interestingChanges)1908 public static boolean needNewResources(@Config int configChanges, 1909 @Config int interestingChanges) { 1910 // CONFIG_ASSETS_PATHS and CONFIG_FONT_SCALE are higher level configuration changes that 1911 // all resources are subject to change with. 1912 interestingChanges = interestingChanges | ActivityInfo.CONFIG_ASSETS_PATHS 1913 | ActivityInfo.CONFIG_FONT_SCALE; 1914 return (configChanges & interestingChanges) != 0; 1915 } 1916 1917 /** 1918 * @hide Return true if the sequence of 'other' is better than this. Assumes 1919 * that 'this' is your current sequence and 'other' is a new one you have 1920 * received some how and want to compare with what you have. 1921 */ isOtherSeqNewer(Configuration other)1922 public boolean isOtherSeqNewer(Configuration other) { 1923 if (other == null) { 1924 // Validation check. 1925 return false; 1926 } 1927 if (other.seq == 0) { 1928 // If the other sequence is not specified, then we must assume 1929 // it is newer since we don't know any better. 1930 return true; 1931 } 1932 if (seq == 0) { 1933 // If this sequence is not specified, then we also consider the 1934 // other is better. Yes we have a preference for other. Sue us. 1935 return true; 1936 } 1937 int diff = other.seq - seq; 1938 if (diff > 0x10000) { 1939 // If there has been a sufficiently large jump, assume the 1940 // sequence has wrapped around. 1941 return false; 1942 } 1943 return diff > 0; 1944 } 1945 1946 /** 1947 * Parcelable methods 1948 */ describeContents()1949 public int describeContents() { 1950 return 0; 1951 } 1952 writeToParcel(Parcel dest, int flags)1953 public void writeToParcel(Parcel dest, int flags) { 1954 dest.writeFloat(fontScale); 1955 dest.writeInt(mcc); 1956 dest.writeInt(mnc); 1957 1958 fixUpLocaleList(); 1959 dest.writeTypedObject(mLocaleList, flags); 1960 1961 if(userSetLocale) { 1962 dest.writeInt(1); 1963 } else { 1964 dest.writeInt(0); 1965 } 1966 dest.writeInt(touchscreen); 1967 dest.writeInt(keyboard); 1968 dest.writeInt(keyboardHidden); 1969 dest.writeInt(hardKeyboardHidden); 1970 dest.writeInt(navigation); 1971 dest.writeInt(navigationHidden); 1972 dest.writeInt(orientation); 1973 dest.writeInt(screenLayout); 1974 dest.writeInt(colorMode); 1975 dest.writeInt(uiMode); 1976 dest.writeInt(screenWidthDp); 1977 dest.writeInt(screenHeightDp); 1978 dest.writeInt(smallestScreenWidthDp); 1979 dest.writeInt(densityDpi); 1980 dest.writeInt(compatScreenWidthDp); 1981 dest.writeInt(compatScreenHeightDp); 1982 dest.writeInt(compatSmallestScreenWidthDp); 1983 windowConfiguration.writeToParcel(dest, flags); 1984 dest.writeInt(assetsSeq); 1985 dest.writeInt(seq); 1986 dest.writeInt(fontWeightAdjustment); 1987 } 1988 readFromParcel(Parcel source)1989 public void readFromParcel(Parcel source) { 1990 fontScale = source.readFloat(); 1991 mcc = source.readInt(); 1992 mnc = source.readInt(); 1993 1994 mLocaleList = source.readTypedObject(LocaleList.CREATOR); 1995 locale = mLocaleList.get(0); 1996 1997 userSetLocale = (source.readInt()==1); 1998 touchscreen = source.readInt(); 1999 keyboard = source.readInt(); 2000 keyboardHidden = source.readInt(); 2001 hardKeyboardHidden = source.readInt(); 2002 navigation = source.readInt(); 2003 navigationHidden = source.readInt(); 2004 orientation = source.readInt(); 2005 screenLayout = source.readInt(); 2006 colorMode = source.readInt(); 2007 uiMode = source.readInt(); 2008 screenWidthDp = source.readInt(); 2009 screenHeightDp = source.readInt(); 2010 smallestScreenWidthDp = source.readInt(); 2011 densityDpi = source.readInt(); 2012 compatScreenWidthDp = source.readInt(); 2013 compatScreenHeightDp = source.readInt(); 2014 compatSmallestScreenWidthDp = source.readInt(); 2015 windowConfiguration.readFromParcel(source); 2016 assetsSeq = source.readInt(); 2017 seq = source.readInt(); 2018 fontWeightAdjustment = source.readInt(); 2019 } 2020 2021 public static final @android.annotation.NonNull Parcelable.Creator<Configuration> CREATOR 2022 = new Parcelable.Creator<Configuration>() { 2023 public Configuration createFromParcel(Parcel source) { 2024 return new Configuration(source); 2025 } 2026 2027 public Configuration[] newArray(int size) { 2028 return new Configuration[size]; 2029 } 2030 }; 2031 2032 /** 2033 * Construct this Configuration object, reading from the Parcel. 2034 */ Configuration(Parcel source)2035 private Configuration(Parcel source) { 2036 readFromParcel(source); 2037 } 2038 2039 2040 /** 2041 * Retuns whether the configuration is in night mode 2042 * @return true if night mode is active and false otherwise 2043 */ isNightModeActive()2044 public boolean isNightModeActive() { 2045 return (uiMode & UI_MODE_NIGHT_MASK) == UI_MODE_NIGHT_YES; 2046 } 2047 compareTo(Configuration that)2048 public int compareTo(Configuration that) { 2049 int n; 2050 float a = this.fontScale; 2051 float b = that.fontScale; 2052 if (a < b) return -1; 2053 if (a > b) return 1; 2054 n = this.mcc - that.mcc; 2055 if (n != 0) return n; 2056 n = this.mnc - that.mnc; 2057 if (n != 0) return n; 2058 2059 fixUpLocaleList(); 2060 that.fixUpLocaleList(); 2061 // for backward compatibility, we consider an empty locale list to be greater 2062 // than any non-empty locale list. 2063 if (this.mLocaleList.isEmpty()) { 2064 if (!that.mLocaleList.isEmpty()) return 1; 2065 } else if (that.mLocaleList.isEmpty()) { 2066 return -1; 2067 } else { 2068 final int minSize = Math.min(this.mLocaleList.size(), that.mLocaleList.size()); 2069 for (int i = 0; i < minSize; ++i) { 2070 final Locale thisLocale = this.mLocaleList.get(i); 2071 final Locale thatLocale = that.mLocaleList.get(i); 2072 n = thisLocale.getLanguage().compareTo(thatLocale.getLanguage()); 2073 if (n != 0) return n; 2074 n = thisLocale.getCountry().compareTo(thatLocale.getCountry()); 2075 if (n != 0) return n; 2076 n = thisLocale.getVariant().compareTo(thatLocale.getVariant()); 2077 if (n != 0) return n; 2078 n = thisLocale.toLanguageTag().compareTo(thatLocale.toLanguageTag()); 2079 if (n != 0) return n; 2080 } 2081 n = this.mLocaleList.size() - that.mLocaleList.size(); 2082 if (n != 0) return n; 2083 } 2084 2085 n = this.touchscreen - that.touchscreen; 2086 if (n != 0) return n; 2087 n = this.keyboard - that.keyboard; 2088 if (n != 0) return n; 2089 n = this.keyboardHidden - that.keyboardHidden; 2090 if (n != 0) return n; 2091 n = this.hardKeyboardHidden - that.hardKeyboardHidden; 2092 if (n != 0) return n; 2093 n = this.navigation - that.navigation; 2094 if (n != 0) return n; 2095 n = this.navigationHidden - that.navigationHidden; 2096 if (n != 0) return n; 2097 n = this.orientation - that.orientation; 2098 if (n != 0) return n; 2099 n = this.colorMode - that.colorMode; 2100 if (n != 0) return n; 2101 n = this.screenLayout - that.screenLayout; 2102 if (n != 0) return n; 2103 n = this.uiMode - that.uiMode; 2104 if (n != 0) return n; 2105 n = this.screenWidthDp - that.screenWidthDp; 2106 if (n != 0) return n; 2107 n = this.screenHeightDp - that.screenHeightDp; 2108 if (n != 0) return n; 2109 n = this.smallestScreenWidthDp - that.smallestScreenWidthDp; 2110 if (n != 0) return n; 2111 n = this.densityDpi - that.densityDpi; 2112 if (n != 0) return n; 2113 n = this.assetsSeq - that.assetsSeq; 2114 if (n != 0) return n; 2115 n = windowConfiguration.compareTo(that.windowConfiguration); 2116 if (n != 0) return n; 2117 n = this.fontWeightAdjustment - that.fontWeightAdjustment; 2118 if (n != 0) return n; 2119 2120 // if (n != 0) return n; 2121 return n; 2122 } 2123 equals(Configuration that)2124 public boolean equals(Configuration that) { 2125 if (that == null) return false; 2126 if (that == this) return true; 2127 return this.compareTo(that) == 0; 2128 } 2129 equals(@ullable Object that)2130 public boolean equals(@Nullable Object that) { 2131 try { 2132 return equals((Configuration)that); 2133 } catch (ClassCastException e) { 2134 } 2135 return false; 2136 } 2137 hashCode()2138 public int hashCode() { 2139 int result = 17; 2140 result = 31 * result + Float.floatToIntBits(fontScale); 2141 result = 31 * result + mcc; 2142 result = 31 * result + mnc; 2143 result = 31 * result + mLocaleList.hashCode(); 2144 result = 31 * result + touchscreen; 2145 result = 31 * result + keyboard; 2146 result = 31 * result + keyboardHidden; 2147 result = 31 * result + hardKeyboardHidden; 2148 result = 31 * result + navigation; 2149 result = 31 * result + navigationHidden; 2150 result = 31 * result + orientation; 2151 result = 31 * result + screenLayout; 2152 result = 31 * result + colorMode; 2153 result = 31 * result + uiMode; 2154 result = 31 * result + screenWidthDp; 2155 result = 31 * result + screenHeightDp; 2156 result = 31 * result + smallestScreenWidthDp; 2157 result = 31 * result + densityDpi; 2158 result = 31 * result + assetsSeq; 2159 result = 31 * result + fontWeightAdjustment; 2160 return result; 2161 } 2162 2163 /** 2164 * Get the locale list. This is the preferred way for getting the locales (instead of using 2165 * the direct accessor to {@link #locale}, which would only provide the primary locale). 2166 * 2167 * @return The locale list. 2168 */ getLocales()2169 public @NonNull LocaleList getLocales() { 2170 fixUpLocaleList(); 2171 return mLocaleList; 2172 } 2173 2174 /** 2175 * Set the locale list. This is the preferred way for setting up the locales (instead of using 2176 * the direct accessor or {@link #setLocale(Locale)}). This will also set the layout direction 2177 * according to the first locale in the list. 2178 * 2179 * Note that the layout direction will always come from the first locale in the locale list, 2180 * even if the locale is not supported by the resources (the resources may only support 2181 * another locale further down the list which has a different direction). 2182 * 2183 * @param locales The locale list. If null, an empty LocaleList will be assigned. 2184 */ setLocales(@ullable LocaleList locales)2185 public void setLocales(@Nullable LocaleList locales) { 2186 mLocaleList = locales == null ? LocaleList.getEmptyLocaleList() : locales; 2187 locale = mLocaleList.get(0); 2188 setLayoutDirection(locale); 2189 } 2190 2191 /** 2192 * Set the locale list to a list of just one locale. This will also set the layout direction 2193 * according to the locale. 2194 * 2195 * Note that after this is run, calling <code>.equals()</code> on the input locale and the 2196 * {@link #locale} attribute would return <code>true</code> if they are not null, but there is 2197 * no guarantee that they would be the same object. 2198 * 2199 * See also the note about layout direction in {@link #setLocales(LocaleList)}. 2200 * 2201 * @param loc The locale. Can be null. 2202 */ setLocale(@ullable Locale loc)2203 public void setLocale(@Nullable Locale loc) { 2204 setLocales(loc == null ? LocaleList.getEmptyLocaleList() : new LocaleList(loc)); 2205 } 2206 2207 /** 2208 * @hide 2209 * 2210 * Clears the locale without changing layout direction. 2211 */ clearLocales()2212 public void clearLocales() { 2213 mLocaleList = LocaleList.getEmptyLocaleList(); 2214 locale = null; 2215 } 2216 2217 /** 2218 * Return the layout direction. Will be either {@link View#LAYOUT_DIRECTION_LTR} or 2219 * {@link View#LAYOUT_DIRECTION_RTL}. 2220 * 2221 * @return Returns {@link View#LAYOUT_DIRECTION_RTL} if the configuration 2222 * is {@link #SCREENLAYOUT_LAYOUTDIR_RTL}, otherwise {@link View#LAYOUT_DIRECTION_LTR}. 2223 */ getLayoutDirection()2224 public int getLayoutDirection() { 2225 return (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK) == SCREENLAYOUT_LAYOUTDIR_RTL 2226 ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR; 2227 } 2228 2229 /** 2230 * Set the layout direction from a Locale. 2231 * 2232 * @param loc The Locale. If null will set the layout direction to 2233 * {@link View#LAYOUT_DIRECTION_LTR}. If not null will set it to the layout direction 2234 * corresponding to the Locale. 2235 * 2236 * @see View#LAYOUT_DIRECTION_LTR 2237 * @see View#LAYOUT_DIRECTION_RTL 2238 */ setLayoutDirection(Locale loc)2239 public void setLayoutDirection(Locale loc) { 2240 // There is a "1" difference between the configuration values for 2241 // layout direction and View constants for layout direction, just add "1". 2242 final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(loc); 2243 screenLayout = (screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK)| 2244 (layoutDirection << SCREENLAYOUT_LAYOUTDIR_SHIFT); 2245 } 2246 getScreenLayoutNoDirection(int screenLayout)2247 private static int getScreenLayoutNoDirection(int screenLayout) { 2248 return screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK; 2249 } 2250 2251 /** 2252 * Return whether the screen has a round shape. Apps may choose to change styling based 2253 * on this property, such as the alignment or layout of text or informational icons. 2254 * 2255 * @return true if the screen is rounded, false otherwise 2256 */ isScreenRound()2257 public boolean isScreenRound() { 2258 return (screenLayout & SCREENLAYOUT_ROUND_MASK) == SCREENLAYOUT_ROUND_YES; 2259 } 2260 2261 /** 2262 * Return whether the screen has a wide color gamut and wide color gamut rendering 2263 * is supported by this device. 2264 * 2265 * When true, it implies the screen is colorspace aware but not 2266 * necessarily color-managed. The final colors may still be changed by the 2267 * screen depending on user settings. 2268 * 2269 * @return true if the screen has a wide color gamut and wide color gamut rendering 2270 * is supported, false otherwise 2271 */ isScreenWideColorGamut()2272 public boolean isScreenWideColorGamut() { 2273 return (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) == COLOR_MODE_WIDE_COLOR_GAMUT_YES; 2274 } 2275 2276 /** 2277 * Return whether the screen has a high dynamic range. 2278 * 2279 * @return true if the screen has a high dynamic range, false otherwise 2280 */ isScreenHdr()2281 public boolean isScreenHdr() { 2282 return (colorMode & COLOR_MODE_HDR_MASK) == COLOR_MODE_HDR_YES; 2283 } 2284 2285 /** 2286 * 2287 * @hide 2288 */ localesToResourceQualifier(LocaleList locs)2289 public static String localesToResourceQualifier(LocaleList locs) { 2290 final StringBuilder sb = new StringBuilder(); 2291 for (int i = 0; i < locs.size(); i++) { 2292 final Locale loc = locs.get(i); 2293 final int l = loc.getLanguage().length(); 2294 if (l == 0) { 2295 continue; 2296 } 2297 final int s = loc.getScript().length(); 2298 final int c = loc.getCountry().length(); 2299 final int v = loc.getVariant().length(); 2300 // We ignore locale extensions, since they are not supported by AAPT 2301 2302 if (sb.length() != 0) { 2303 sb.append(","); 2304 } 2305 if (l == 2 && s == 0 && (c == 0 || c == 2) && v == 0) { 2306 // Traditional locale format: xx or xx-rYY 2307 sb.append(loc.getLanguage()); 2308 if (c == 2) { 2309 sb.append("-r").append(loc.getCountry()); 2310 } 2311 } else { 2312 sb.append("b+"); 2313 sb.append(loc.getLanguage()); 2314 if (s != 0) { 2315 sb.append("+"); 2316 sb.append(loc.getScript()); 2317 } 2318 if (c != 0) { 2319 sb.append("+"); 2320 sb.append(loc.getCountry()); 2321 } 2322 if (v != 0) { 2323 sb.append("+"); 2324 sb.append(loc.getVariant()); 2325 } 2326 } 2327 } 2328 return sb.toString(); 2329 } 2330 2331 2332 /** 2333 * Returns a string representation of the configuration that can be parsed 2334 * by build tools (like AAPT), without display metrics included 2335 * 2336 * @hide 2337 */ 2338 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) resourceQualifierString(Configuration config)2339 public static String resourceQualifierString(Configuration config) { 2340 return resourceQualifierString(config, null); 2341 } 2342 2343 /** 2344 * Returns a string representation of the configuration that can be parsed 2345 * by build tools (like AAPT). 2346 * 2347 * @hide 2348 */ resourceQualifierString(Configuration config, DisplayMetrics metrics)2349 public static String resourceQualifierString(Configuration config, DisplayMetrics metrics) { 2350 ArrayList<String> parts = new ArrayList<String>(); 2351 2352 if (config.mcc != 0) { 2353 parts.add("mcc" + config.mcc); 2354 if (config.mnc != 0) { 2355 parts.add("mnc" + config.mnc); 2356 } 2357 } 2358 2359 if (!config.mLocaleList.isEmpty()) { 2360 final String resourceQualifier = localesToResourceQualifier(config.mLocaleList); 2361 if (!resourceQualifier.isEmpty()) { 2362 parts.add(resourceQualifier); 2363 } 2364 } 2365 2366 switch (config.screenLayout & Configuration.SCREENLAYOUT_LAYOUTDIR_MASK) { 2367 case Configuration.SCREENLAYOUT_LAYOUTDIR_LTR: 2368 parts.add("ldltr"); 2369 break; 2370 case Configuration.SCREENLAYOUT_LAYOUTDIR_RTL: 2371 parts.add("ldrtl"); 2372 break; 2373 default: 2374 break; 2375 } 2376 2377 if (config.smallestScreenWidthDp != 0) { 2378 parts.add("sw" + config.smallestScreenWidthDp + "dp"); 2379 } 2380 2381 if (config.screenWidthDp != 0) { 2382 parts.add("w" + config.screenWidthDp + "dp"); 2383 } 2384 2385 if (config.screenHeightDp != 0) { 2386 parts.add("h" + config.screenHeightDp + "dp"); 2387 } 2388 2389 switch (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) { 2390 case Configuration.SCREENLAYOUT_SIZE_SMALL: 2391 parts.add("small"); 2392 break; 2393 case Configuration.SCREENLAYOUT_SIZE_NORMAL: 2394 parts.add("normal"); 2395 break; 2396 case Configuration.SCREENLAYOUT_SIZE_LARGE: 2397 parts.add("large"); 2398 break; 2399 case Configuration.SCREENLAYOUT_SIZE_XLARGE: 2400 parts.add("xlarge"); 2401 break; 2402 default: 2403 break; 2404 } 2405 2406 switch (config.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK) { 2407 case Configuration.SCREENLAYOUT_LONG_YES: 2408 parts.add("long"); 2409 break; 2410 case Configuration.SCREENLAYOUT_LONG_NO: 2411 parts.add("notlong"); 2412 break; 2413 default: 2414 break; 2415 } 2416 2417 switch (config.screenLayout & Configuration.SCREENLAYOUT_ROUND_MASK) { 2418 case Configuration.SCREENLAYOUT_ROUND_YES: 2419 parts.add("round"); 2420 break; 2421 case Configuration.SCREENLAYOUT_ROUND_NO: 2422 parts.add("notround"); 2423 break; 2424 default: 2425 break; 2426 } 2427 2428 switch (config.colorMode & Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_MASK) { 2429 case Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_YES: 2430 parts.add("widecg"); 2431 break; 2432 case Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_NO: 2433 parts.add("nowidecg"); 2434 break; 2435 default: 2436 break; 2437 } 2438 2439 switch (config.colorMode & Configuration.COLOR_MODE_HDR_MASK) { 2440 case Configuration.COLOR_MODE_HDR_YES: 2441 parts.add("highdr"); 2442 break; 2443 case Configuration.COLOR_MODE_HDR_NO: 2444 parts.add("lowdr"); 2445 break; 2446 default: 2447 break; 2448 } 2449 2450 switch (config.orientation) { 2451 case Configuration.ORIENTATION_LANDSCAPE: 2452 parts.add("land"); 2453 break; 2454 case Configuration.ORIENTATION_PORTRAIT: 2455 parts.add("port"); 2456 break; 2457 default: 2458 break; 2459 } 2460 2461 switch (config.uiMode & Configuration.UI_MODE_TYPE_MASK) { 2462 case Configuration.UI_MODE_TYPE_APPLIANCE: 2463 parts.add("appliance"); 2464 break; 2465 case Configuration.UI_MODE_TYPE_DESK: 2466 parts.add("desk"); 2467 break; 2468 case Configuration.UI_MODE_TYPE_TELEVISION: 2469 parts.add("television"); 2470 break; 2471 case Configuration.UI_MODE_TYPE_CAR: 2472 parts.add("car"); 2473 break; 2474 case Configuration.UI_MODE_TYPE_WATCH: 2475 parts.add("watch"); 2476 break; 2477 case Configuration.UI_MODE_TYPE_VR_HEADSET: 2478 parts.add("vrheadset"); 2479 break; 2480 default: 2481 break; 2482 } 2483 2484 switch (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) { 2485 case Configuration.UI_MODE_NIGHT_YES: 2486 parts.add("night"); 2487 break; 2488 case Configuration.UI_MODE_NIGHT_NO: 2489 parts.add("notnight"); 2490 break; 2491 default: 2492 break; 2493 } 2494 2495 switch (config.densityDpi) { 2496 case DENSITY_DPI_UNDEFINED: 2497 break; 2498 case 120: 2499 parts.add("ldpi"); 2500 break; 2501 case 160: 2502 parts.add("mdpi"); 2503 break; 2504 case 213: 2505 parts.add("tvdpi"); 2506 break; 2507 case 240: 2508 parts.add("hdpi"); 2509 break; 2510 case 320: 2511 parts.add("xhdpi"); 2512 break; 2513 case 480: 2514 parts.add("xxhdpi"); 2515 break; 2516 case 640: 2517 parts.add("xxxhdpi"); 2518 break; 2519 case DENSITY_DPI_ANY: 2520 parts.add("anydpi"); 2521 break; 2522 case DENSITY_DPI_NONE: 2523 parts.add("nodpi"); 2524 break; 2525 default: 2526 parts.add(config.densityDpi + "dpi"); 2527 break; 2528 } 2529 2530 switch (config.touchscreen) { 2531 case Configuration.TOUCHSCREEN_NOTOUCH: 2532 parts.add("notouch"); 2533 break; 2534 case Configuration.TOUCHSCREEN_FINGER: 2535 parts.add("finger"); 2536 break; 2537 default: 2538 break; 2539 } 2540 2541 switch (config.keyboardHidden) { 2542 case Configuration.KEYBOARDHIDDEN_NO: 2543 parts.add("keysexposed"); 2544 break; 2545 case Configuration.KEYBOARDHIDDEN_YES: 2546 parts.add("keyshidden"); 2547 break; 2548 case Configuration.KEYBOARDHIDDEN_SOFT: 2549 parts.add("keyssoft"); 2550 break; 2551 default: 2552 break; 2553 } 2554 2555 switch (config.keyboard) { 2556 case Configuration.KEYBOARD_NOKEYS: 2557 parts.add("nokeys"); 2558 break; 2559 case Configuration.KEYBOARD_QWERTY: 2560 parts.add("qwerty"); 2561 break; 2562 case Configuration.KEYBOARD_12KEY: 2563 parts.add("12key"); 2564 break; 2565 default: 2566 break; 2567 } 2568 2569 switch (config.navigationHidden) { 2570 case Configuration.NAVIGATIONHIDDEN_NO: 2571 parts.add("navexposed"); 2572 break; 2573 case Configuration.NAVIGATIONHIDDEN_YES: 2574 parts.add("navhidden"); 2575 break; 2576 default: 2577 break; 2578 } 2579 2580 switch (config.navigation) { 2581 case Configuration.NAVIGATION_NONAV: 2582 parts.add("nonav"); 2583 break; 2584 case Configuration.NAVIGATION_DPAD: 2585 parts.add("dpad"); 2586 break; 2587 case Configuration.NAVIGATION_TRACKBALL: 2588 parts.add("trackball"); 2589 break; 2590 case Configuration.NAVIGATION_WHEEL: 2591 parts.add("wheel"); 2592 break; 2593 default: 2594 break; 2595 } 2596 2597 if (metrics != null) { 2598 final int width, height; 2599 if (metrics.widthPixels >= metrics.heightPixels) { 2600 width = metrics.widthPixels; 2601 height = metrics.heightPixels; 2602 } else { 2603 //noinspection SuspiciousNameCombination 2604 width = metrics.heightPixels; 2605 //noinspection SuspiciousNameCombination 2606 height = metrics.widthPixels; 2607 } 2608 parts.add(width + "x" + height); 2609 } 2610 2611 parts.add("v" + Build.VERSION.RESOURCES_SDK_INT); 2612 return TextUtils.join("-", parts); 2613 } 2614 2615 /** 2616 * Generate a delta Configuration between <code>base</code> and <code>change</code>. The 2617 * resulting delta can be used with {@link #updateFrom(Configuration)}. 2618 * <p /> 2619 * Caveat: If the any of the Configuration's members becomes undefined, then 2620 * {@link #updateFrom(Configuration)} will treat it as a no-op and not update that member. 2621 * 2622 * This is fine for device configurations as no member is ever undefined. 2623 * {@hide} 2624 */ 2625 @UnsupportedAppUsage generateDelta(Configuration base, Configuration change)2626 public static Configuration generateDelta(Configuration base, Configuration change) { 2627 final Configuration delta = new Configuration(); 2628 if (base.fontScale != change.fontScale) { 2629 delta.fontScale = change.fontScale; 2630 } 2631 2632 if (base.mcc != change.mcc) { 2633 delta.mcc = change.mcc; 2634 } 2635 2636 if (base.mnc != change.mnc) { 2637 delta.mnc = change.mnc; 2638 } 2639 2640 base.fixUpLocaleList(); 2641 change.fixUpLocaleList(); 2642 if (!base.mLocaleList.equals(change.mLocaleList)) { 2643 delta.mLocaleList = change.mLocaleList; 2644 delta.locale = change.locale; 2645 } 2646 2647 if (base.touchscreen != change.touchscreen) { 2648 delta.touchscreen = change.touchscreen; 2649 } 2650 2651 if (base.keyboard != change.keyboard) { 2652 delta.keyboard = change.keyboard; 2653 } 2654 2655 if (base.keyboardHidden != change.keyboardHidden) { 2656 delta.keyboardHidden = change.keyboardHidden; 2657 } 2658 2659 if (base.navigation != change.navigation) { 2660 delta.navigation = change.navigation; 2661 } 2662 2663 if (base.navigationHidden != change.navigationHidden) { 2664 delta.navigationHidden = change.navigationHidden; 2665 } 2666 2667 if (base.orientation != change.orientation) { 2668 delta.orientation = change.orientation; 2669 } 2670 2671 if ((base.screenLayout & SCREENLAYOUT_SIZE_MASK) != 2672 (change.screenLayout & SCREENLAYOUT_SIZE_MASK)) { 2673 delta.screenLayout |= change.screenLayout & SCREENLAYOUT_SIZE_MASK; 2674 } 2675 2676 if ((base.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK) != 2677 (change.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) { 2678 delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK; 2679 } 2680 2681 if ((base.screenLayout & SCREENLAYOUT_LONG_MASK) != 2682 (change.screenLayout & SCREENLAYOUT_LONG_MASK)) { 2683 delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LONG_MASK; 2684 } 2685 2686 if ((base.screenLayout & SCREENLAYOUT_ROUND_MASK) != 2687 (change.screenLayout & SCREENLAYOUT_ROUND_MASK)) { 2688 delta.screenLayout |= change.screenLayout & SCREENLAYOUT_ROUND_MASK; 2689 } 2690 2691 if ((base.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) != 2692 (change.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) { 2693 delta.colorMode |= change.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK; 2694 } 2695 2696 if ((base.colorMode & COLOR_MODE_HDR_MASK) != 2697 (change.colorMode & COLOR_MODE_HDR_MASK)) { 2698 delta.colorMode |= change.colorMode & COLOR_MODE_HDR_MASK; 2699 } 2700 2701 if ((base.uiMode & UI_MODE_TYPE_MASK) != (change.uiMode & UI_MODE_TYPE_MASK)) { 2702 delta.uiMode |= change.uiMode & UI_MODE_TYPE_MASK; 2703 } 2704 2705 if ((base.uiMode & UI_MODE_NIGHT_MASK) != (change.uiMode & UI_MODE_NIGHT_MASK)) { 2706 delta.uiMode |= change.uiMode & UI_MODE_NIGHT_MASK; 2707 } 2708 2709 if (base.screenWidthDp != change.screenWidthDp) { 2710 delta.screenWidthDp = change.screenWidthDp; 2711 } 2712 2713 if (base.screenHeightDp != change.screenHeightDp) { 2714 delta.screenHeightDp = change.screenHeightDp; 2715 } 2716 2717 if (base.smallestScreenWidthDp != change.smallestScreenWidthDp) { 2718 delta.smallestScreenWidthDp = change.smallestScreenWidthDp; 2719 } 2720 2721 if (base.densityDpi != change.densityDpi) { 2722 delta.densityDpi = change.densityDpi; 2723 } 2724 2725 if (base.assetsSeq != change.assetsSeq) { 2726 delta.assetsSeq = change.assetsSeq; 2727 } 2728 2729 if (!base.windowConfiguration.equals(change.windowConfiguration)) { 2730 delta.windowConfiguration.setTo(change.windowConfiguration); 2731 } 2732 2733 if (base.fontWeightAdjustment != change.fontWeightAdjustment) { 2734 delta.fontWeightAdjustment = change.fontWeightAdjustment; 2735 } 2736 return delta; 2737 } 2738 2739 private static final String XML_ATTR_FONT_SCALE = "fs"; 2740 private static final String XML_ATTR_MCC = "mcc"; 2741 private static final String XML_ATTR_MNC = "mnc"; 2742 private static final String XML_ATTR_LOCALES = "locales"; 2743 private static final String XML_ATTR_TOUCHSCREEN = "touch"; 2744 private static final String XML_ATTR_KEYBOARD = "key"; 2745 private static final String XML_ATTR_KEYBOARD_HIDDEN = "keyHid"; 2746 private static final String XML_ATTR_HARD_KEYBOARD_HIDDEN = "hardKeyHid"; 2747 private static final String XML_ATTR_NAVIGATION = "nav"; 2748 private static final String XML_ATTR_NAVIGATION_HIDDEN = "navHid"; 2749 private static final String XML_ATTR_ORIENTATION = "ori"; 2750 private static final String XML_ATTR_ROTATION = "rot"; 2751 private static final String XML_ATTR_SCREEN_LAYOUT = "scrLay"; 2752 private static final String XML_ATTR_COLOR_MODE = "clrMod"; 2753 private static final String XML_ATTR_UI_MODE = "ui"; 2754 private static final String XML_ATTR_SCREEN_WIDTH = "width"; 2755 private static final String XML_ATTR_SCREEN_HEIGHT = "height"; 2756 private static final String XML_ATTR_SMALLEST_WIDTH = "sw"; 2757 private static final String XML_ATTR_DENSITY = "density"; 2758 private static final String XML_ATTR_APP_BOUNDS = "app_bounds"; 2759 private static final String XML_ATTR_FONT_WEIGHT_ADJUSTMENT = "fontWeightAdjustment"; 2760 2761 /** 2762 * Reads the attributes corresponding to Configuration member fields from the Xml parser. 2763 * The parser is expected to be on a tag which has Configuration attributes. 2764 * 2765 * @param parser The Xml parser from which to read attributes. 2766 * @param configOut The Configuration to populate from the Xml attributes. 2767 * {@hide} 2768 */ readXmlAttrs(XmlPullParser parser, Configuration configOut)2769 public static void readXmlAttrs(XmlPullParser parser, Configuration configOut) 2770 throws XmlPullParserException, IOException { 2771 configOut.fontScale = Float.intBitsToFloat( 2772 XmlUtils.readIntAttribute(parser, XML_ATTR_FONT_SCALE, 0)); 2773 configOut.mcc = XmlUtils.readIntAttribute(parser, XML_ATTR_MCC, 0); 2774 configOut.mnc = XmlUtils.readIntAttribute(parser, XML_ATTR_MNC, 0); 2775 2776 final String localesStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALES); 2777 configOut.mLocaleList = LocaleList.forLanguageTags(localesStr); 2778 configOut.locale = configOut.mLocaleList.get(0); 2779 2780 configOut.touchscreen = XmlUtils.readIntAttribute(parser, XML_ATTR_TOUCHSCREEN, 2781 TOUCHSCREEN_UNDEFINED); 2782 configOut.keyboard = XmlUtils.readIntAttribute(parser, XML_ATTR_KEYBOARD, 2783 KEYBOARD_UNDEFINED); 2784 configOut.keyboardHidden = XmlUtils.readIntAttribute(parser, XML_ATTR_KEYBOARD_HIDDEN, 2785 KEYBOARDHIDDEN_UNDEFINED); 2786 configOut.hardKeyboardHidden = 2787 XmlUtils.readIntAttribute(parser, XML_ATTR_HARD_KEYBOARD_HIDDEN, 2788 HARDKEYBOARDHIDDEN_UNDEFINED); 2789 configOut.navigation = XmlUtils.readIntAttribute(parser, XML_ATTR_NAVIGATION, 2790 NAVIGATION_UNDEFINED); 2791 configOut.navigationHidden = XmlUtils.readIntAttribute(parser, XML_ATTR_NAVIGATION_HIDDEN, 2792 NAVIGATIONHIDDEN_UNDEFINED); 2793 configOut.orientation = XmlUtils.readIntAttribute(parser, XML_ATTR_ORIENTATION, 2794 ORIENTATION_UNDEFINED); 2795 configOut.screenLayout = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_LAYOUT, 2796 SCREENLAYOUT_UNDEFINED); 2797 configOut.colorMode = XmlUtils.readIntAttribute(parser, XML_ATTR_COLOR_MODE, 2798 COLOR_MODE_UNDEFINED); 2799 configOut.uiMode = XmlUtils.readIntAttribute(parser, XML_ATTR_UI_MODE, 0); 2800 configOut.screenWidthDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_WIDTH, 2801 SCREEN_WIDTH_DP_UNDEFINED); 2802 configOut.screenHeightDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_HEIGHT, 2803 SCREEN_HEIGHT_DP_UNDEFINED); 2804 configOut.smallestScreenWidthDp = 2805 XmlUtils.readIntAttribute(parser, XML_ATTR_SMALLEST_WIDTH, 2806 SMALLEST_SCREEN_WIDTH_DP_UNDEFINED); 2807 configOut.densityDpi = XmlUtils.readIntAttribute(parser, XML_ATTR_DENSITY, 2808 DENSITY_DPI_UNDEFINED); 2809 configOut.fontWeightAdjustment = XmlUtils.readIntAttribute(parser, 2810 XML_ATTR_FONT_WEIGHT_ADJUSTMENT, FONT_WEIGHT_ADJUSTMENT_UNDEFINED); 2811 2812 // For persistence, we don't care about assetsSeq and WindowConfiguration, so do not read it 2813 // out. 2814 } 2815 } 2816