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