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