/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.content.res; import static android.content.ConfigurationProto.COLOR_MODE; import static android.content.ConfigurationProto.DENSITY_DPI; import static android.content.ConfigurationProto.FONT_SCALE; import static android.content.ConfigurationProto.FONT_WEIGHT_ADJUSTMENT; import static android.content.ConfigurationProto.GRAMMATICAL_GENDER; import static android.content.ConfigurationProto.HARD_KEYBOARD_HIDDEN; import static android.content.ConfigurationProto.KEYBOARD; import static android.content.ConfigurationProto.KEYBOARD_HIDDEN; import static android.content.ConfigurationProto.LOCALES; import static android.content.ConfigurationProto.LOCALE_LIST; import static android.content.ConfigurationProto.MCC; import static android.content.ConfigurationProto.MNC; import static android.content.ConfigurationProto.NAVIGATION; import static android.content.ConfigurationProto.NAVIGATION_HIDDEN; import static android.content.ConfigurationProto.ORIENTATION; import static android.content.ConfigurationProto.SCREEN_HEIGHT_DP; import static android.content.ConfigurationProto.SCREEN_LAYOUT; import static android.content.ConfigurationProto.SCREEN_WIDTH_DP; import static android.content.ConfigurationProto.SMALLEST_SCREEN_WIDTH_DP; import static android.content.ConfigurationProto.TOUCHSCREEN; import static android.content.ConfigurationProto.UI_MODE; import static android.content.ConfigurationProto.WINDOW_CONFIGURATION; import static android.content.ResourcesConfigurationProto.CONFIGURATION; import static android.content.ResourcesConfigurationProto.SCREEN_HEIGHT_PX; import static android.content.ResourcesConfigurationProto.SCREEN_WIDTH_PX; import static android.content.ResourcesConfigurationProto.SDK_VERSION; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.app.GrammaticalInflectionManager; import android.app.WindowConfiguration; import android.compat.annotation.UnsupportedAppUsage; import android.content.LocaleProto; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo.Config; import android.graphics.Typeface; import android.os.Build; import android.os.LocaleList; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Slog; import android.util.proto.ProtoInputStream; import android.util.proto.ProtoOutputStream; import android.util.proto.WireTypeMismatchException; import android.view.View; import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.IllformedLocaleException; import java.util.List; import java.util.Locale; /** * This class describes all device configuration information that can * impact the resources the application retrieves. This includes both * user-specified configuration options (locale list and scaling) as well * as device configurations (such as input modes, screen size and screen orientation). *
You can acquire this object from {@link Resources}, using {@link * Resources#getConfiguration}. Thus, from an activity, you can get it by chaining the request * with {@link android.app.Activity#getResources}:
*Configuration config = getResources().getConfiguration();*/ public final class Configuration implements Parcelable, Comparable
Note: Please do not use this to hardcode font size equations. The equation for font * scaling is now non-linear; this coefficient is no longer used as a direct multiplier to * determine font size. It exists for informational purposes only. * *
Please use {@link android.util.TypedValue#applyDimension(int, float, DisplayMetrics)} or
* {@link android.util.TypedValue#deriveDimension(int, float, DisplayMetrics)} to convert
* between scaled font size dimensions and pixels.
*/
public float fontScale;
/**
* IMSI MCC (Mobile Country Code), corresponding to
* mcc
* resource qualifier. 0 if undefined.
*/
public int mcc;
/**
* IMSI MNC (Mobile Network Code), corresponding to
* mnc
* resource qualifier. 0 if undefined. Note that the actual MNC may be 0; in order to check
* for this use the {@link #MNC_ZERO} symbol.
*/
public int mnc;
/**
* Constant used to to represent MNC (Mobile Network Code) zero.
* 0 cannot be used, since it is used to represent an undefined MNC.
*/
public static final int MNC_ZERO = 0xffff;
/**
* Current user preference for the locale, corresponding to
* locale
* resource qualifier.
*
* @deprecated Do not set or read this directly. Use {@link #getLocales()} and
* {@link #setLocales(LocaleList)}. If only the primary locale is needed,
* getLocales().get(0)
is now the preferred accessor.
*/
@Deprecated public Locale locale;
private LocaleList mLocaleList;
/**
* Locale should persist on setting. This is hidden because it is really
* questionable whether this is the right way to expose the functionality.
* @hide
*/
@UnsupportedAppUsage
public boolean userSetLocale;
/**
* Current user preference for the grammatical gender.
*/
private int mGrammaticalGender;
/** @hide */
@IntDef(prefix = { "GRAMMATICAL_GENDER_" }, value = {
GRAMMATICAL_GENDER_NOT_SPECIFIED,
GRAMMATICAL_GENDER_NEUTRAL,
GRAMMATICAL_GENDER_FEMININE,
GRAMMATICAL_GENDER_MASCULINE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface GrammaticalGender {}
/**
* Constant for grammatical gender: to indicate that the grammatical gender is undefined.
* Only for internal usage.
* @hide
*/
public static final int GRAMMATICAL_GENDER_UNDEFINED = -1;
/**
* Constant for grammatical gender: to indicate the user has not specified the terms
* of address for the application.
*/
public static final int GRAMMATICAL_GENDER_NOT_SPECIFIED = 0;
/**
* Constant for grammatical gender: to indicate the terms of address the user
* preferred in an application is neuter.
*/
public static final int GRAMMATICAL_GENDER_NEUTRAL = 1;
/**
* Constant for grammatical gender: to indicate the terms of address the user
* preferred in an application is feminine.
*/
public static final int GRAMMATICAL_GENDER_FEMININE = 2;
/**
* Constant for grammatical gender: to indicate the terms of address the user
* preferred in an application is masculine.
*/
public static final int GRAMMATICAL_GENDER_MASCULINE = 3;
/** Constant for {@link #colorMode}: bits that encode whether the screen is wide gamut. */
public static final int COLOR_MODE_WIDE_COLOR_GAMUT_MASK = 0x3;
/**
* Constant for {@link #colorMode}: a {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} value
* indicating that it is unknown whether or not the screen is wide gamut.
*/
public static final int COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED = 0x0;
/**
* Constant for {@link #colorMode}: a {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} value
* indicating that the screen is not wide gamut.
*
Corresponds to the -nowidecg
resource qualifier.
Corresponds to the -widecg
resource qualifier.
Corresponds to the -lowdr
resource qualifier.
Corresponds to the -highdr
resource qualifier.
The {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} bits define the color gamut of * the screen. They may be one of * {@link #COLOR_MODE_WIDE_COLOR_GAMUT_NO} or {@link #COLOR_MODE_WIDE_COLOR_GAMUT_YES}.
* *The {@link #COLOR_MODE_HDR_MASK} defines the dynamic range of the screen. They may be * one of {@link #COLOR_MODE_HDR_NO} or {@link #COLOR_MODE_HDR_YES}.
* *See Supporting * Multiple Screens for more information.
*/ public int colorMode; /** Constant for {@link #screenLayout}: bits that encode the size. */ public static final int SCREENLAYOUT_SIZE_MASK = 0x0f; /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK} * value indicating that no size has been set. */ public static final int SCREENLAYOUT_SIZE_UNDEFINED = 0x00; /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK} * value indicating the screen is at least approximately 320x426 dp units, * corresponds to the * small * resource qualifier. * See Supporting * Multiple Screens for more information. */ public static final int SCREENLAYOUT_SIZE_SMALL = 0x01; /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK} * value indicating the screen is at least approximately 320x470 dp units, * corresponds to the * normal * resource qualifier. * See Supporting * Multiple Screens for more information. */ public static final int SCREENLAYOUT_SIZE_NORMAL = 0x02; /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK} * value indicating the screen is at least approximately 480x640 dp units, * corresponds to the * large * resource qualifier. * See Supporting * Multiple Screens for more information. */ public static final int SCREENLAYOUT_SIZE_LARGE = 0x03; /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK} * value indicating the screen is at least approximately 720x960 dp units, * corresponds to the * xlarge * resource qualifier. * See Supporting * Multiple Screens for more information.*/ public static final int SCREENLAYOUT_SIZE_XLARGE = 0x04; /** Constant for {@link #screenLayout}: bits that encode the aspect ratio. */ public static final int SCREENLAYOUT_LONG_MASK = 0x30; /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK} * value indicating that no size has been set. */ public static final int SCREENLAYOUT_LONG_UNDEFINED = 0x00; /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK} * value that corresponds to the * notlong * resource qualifier. */ public static final int SCREENLAYOUT_LONG_NO = 0x10; /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK} * value that corresponds to the * long * resource qualifier. */ public static final int SCREENLAYOUT_LONG_YES = 0x20; /** Constant for {@link #screenLayout}: bits that encode the layout direction. */ public static final int SCREENLAYOUT_LAYOUTDIR_MASK = 0xC0; /** Constant for {@link #screenLayout}: bits shift to get the layout direction. */ public static final int SCREENLAYOUT_LAYOUTDIR_SHIFT = 6; /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK} * value indicating that no layout dir has been set. */ public static final int SCREENLAYOUT_LAYOUTDIR_UNDEFINED = 0x00; /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK} * value indicating that a layout dir has been set to LTR. */ public static final int SCREENLAYOUT_LAYOUTDIR_LTR = 0x01 << SCREENLAYOUT_LAYOUTDIR_SHIFT; /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK} * value indicating that a layout dir has been set to RTL. */ public static final int SCREENLAYOUT_LAYOUTDIR_RTL = 0x02 << SCREENLAYOUT_LAYOUTDIR_SHIFT; /** Constant for {@link #screenLayout}: bits that encode roundness of the screen. */ public static final int SCREENLAYOUT_ROUND_MASK = 0x300; /** @hide Constant for {@link #screenLayout}: bit shift to get to screen roundness bits */ public static final int SCREENLAYOUT_ROUND_SHIFT = 8; /** * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating * that it is unknown whether or not the screen has a round shape. */ public static final int SCREENLAYOUT_ROUND_UNDEFINED = 0x00; /** * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating * that the screen does not have a rounded shape. */ public static final int SCREENLAYOUT_ROUND_NO = 0x1 << SCREENLAYOUT_ROUND_SHIFT; /** * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating * that the screen has a rounded shape. Corners may not be visible to the user; * developers should pay special attention to the {@link android.view.WindowInsets} delivered * to views for more information about ensuring content is not obscured. * *Corresponds to the -round
resource qualifier.
The {@link #SCREENLAYOUT_SIZE_MASK} bits define the overall size * of the screen. They may be one of * {@link #SCREENLAYOUT_SIZE_SMALL}, {@link #SCREENLAYOUT_SIZE_NORMAL}, * {@link #SCREENLAYOUT_SIZE_LARGE}, or {@link #SCREENLAYOUT_SIZE_XLARGE}.
* *The {@link #SCREENLAYOUT_LONG_MASK} defines whether the screen * is wider/taller than normal. They may be one of * {@link #SCREENLAYOUT_LONG_NO} or {@link #SCREENLAYOUT_LONG_YES}.
* *The {@link #SCREENLAYOUT_LAYOUTDIR_MASK} defines whether the screen layout * is either LTR or RTL. They may be one of * {@link #SCREENLAYOUT_LAYOUTDIR_LTR} or {@link #SCREENLAYOUT_LAYOUTDIR_RTL}.
* *The {@link #SCREENLAYOUT_ROUND_MASK} defines whether the screen has a rounded * shape. They may be one of {@link #SCREENLAYOUT_ROUND_NO} or {@link #SCREENLAYOUT_ROUND_YES}. *
* *See Supporting * Multiple Screens for more information.
*/ public int screenLayout; /** * An undefined fontWeightAdjustment. */ public static final int FONT_WEIGHT_ADJUSTMENT_UNDEFINED = Integer.MAX_VALUE; /** * Adjustment in text font weight. Used to reflect the current user preference for increasing * font weight. * * If the text font weight is less than the minimum of 1, 1 will be used. If the font weight
* exceeds the maximum of 1000, 1000 will be used.
*
* @see android.graphics.Typeface#create(Typeface, int, boolean)
* @see android.graphics.fonts.FontStyle#FONT_WEIGHT_MIN
* @see android.graphics.fonts.FontStyle#FONT_WEIGHT_MAX
*/
public int fontWeightAdjustment;
/**
* Configuration relating to the windowing state of the object associated with this
* Configuration. Contents of this field are not intended to affect resources, but need to be
* communicated and propagated at the same time as the rest of Configuration.
* @hide
*/
@TestApi
public final WindowConfiguration windowConfiguration = new WindowConfiguration();
/** @hide */
static public int resetScreenLayout(int curLayout) {
return (curLayout&~(SCREENLAYOUT_LONG_MASK | SCREENLAYOUT_SIZE_MASK
| SCREENLAYOUT_COMPAT_NEEDED))
| (SCREENLAYOUT_LONG_YES | SCREENLAYOUT_SIZE_XLARGE);
}
/** @hide */
static public int reduceScreenLayout(int curLayout, int longSizeDp, int shortSizeDp) {
int screenLayoutSize;
boolean screenLayoutLong;
boolean screenLayoutCompatNeeded;
// These semi-magic numbers define our compatibility modes for
// applications with different screens. These are guarantees to
// app developers about the space they can expect for a particular
// configuration. DO NOT CHANGE!
if (longSizeDp < 470) {
// This is shorter than an HVGA normal density screen (which
// is 480 pixels on its long side).
screenLayoutSize = SCREENLAYOUT_SIZE_SMALL;
screenLayoutLong = false;
screenLayoutCompatNeeded = false;
} else {
// What size is this screen screen?
if (longSizeDp >= 960 && shortSizeDp >= 720) {
// 1.5xVGA or larger screens at medium density are the point
// at which we consider it to be an extra large screen.
screenLayoutSize = SCREENLAYOUT_SIZE_XLARGE;
} else if (longSizeDp >= 640 && shortSizeDp >= 480) {
// VGA or larger screens at medium density are the point
// at which we consider it to be a large screen.
screenLayoutSize = SCREENLAYOUT_SIZE_LARGE;
} else {
screenLayoutSize = SCREENLAYOUT_SIZE_NORMAL;
}
// If this screen is wider than normal HVGA, or taller
// than FWVGA, then for old apps we want to run in size
// compatibility mode.
if (shortSizeDp > 321 || longSizeDp > 570) {
screenLayoutCompatNeeded = true;
} else {
screenLayoutCompatNeeded = false;
}
// Is this a long screen?
if (((longSizeDp*3)/5) >= (shortSizeDp-1)) {
// Anything wider than WVGA (5:3) is considering to be long.
screenLayoutLong = true;
} else {
screenLayoutLong = false;
}
}
// Now reduce the last screenLayout to not be better than what we
// have found.
if (!screenLayoutLong) {
curLayout = (curLayout&~SCREENLAYOUT_LONG_MASK) | SCREENLAYOUT_LONG_NO;
}
if (screenLayoutCompatNeeded) {
curLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
}
int curSize = curLayout&SCREENLAYOUT_SIZE_MASK;
if (screenLayoutSize < curSize) {
curLayout = (curLayout&~SCREENLAYOUT_SIZE_MASK) | screenLayoutSize;
}
return curLayout;
}
/** @hide */
public static String configurationDiffToString(int diff) {
ArrayList The {@link #UI_MODE_TYPE_MASK} bits define the overall ui mode of the
* device. They may be one of {@link #UI_MODE_TYPE_UNDEFINED},
* {@link #UI_MODE_TYPE_NORMAL}, {@link #UI_MODE_TYPE_DESK},
* {@link #UI_MODE_TYPE_CAR}, {@link #UI_MODE_TYPE_TELEVISION},
* {@link #UI_MODE_TYPE_APPLIANCE}, {@link #UI_MODE_TYPE_WATCH},
* or {@link #UI_MODE_TYPE_VR_HEADSET}.
*
* The {@link #UI_MODE_NIGHT_MASK} defines whether the screen
* is in a special mode. They may be one of {@link #UI_MODE_NIGHT_UNDEFINED},
* {@link #UI_MODE_NIGHT_NO} or {@link #UI_MODE_NIGHT_YES}.
*/
public int uiMode;
/**
* Default value for {@link #screenWidthDp} indicating that no width
* has been specified.
*/
public static final int SCREEN_WIDTH_DP_UNDEFINED = 0;
/**
* The width of the available screen space in dp units.
*
*
*
* Use {@link android.view.WindowMetrics#getBounds()} to always obtain the horizontal
* display area available to an app or embedded activity including the area
* occupied by window insets. A version of the API is also available for use on older platforms
* through {@link androidx.window.layout.WindowMetrics}.
*
* Corresponds to the
*
* available width resource qualifier. Defaults to
* {@link #SCREEN_WIDTH_DP_UNDEFINED} if no width is specified.
*
* In multi-window mode, equals the width of the available display area
* of the app window, not the available display area of the device screen
* (for example, when apps are displayed side by side in split-screen mode
* in landscape orientation).
*
* For embedded activities, equals the width of the individual
* activities, not the width of the app window or the device screen.
*
* In multiple-screen scenarios, the width measurement can span screens.
* For example, if the app is spanning both screens of a dual-screen device
* (with the screens side by side), {@code screenWidthDp} represents the
* width of both screens excluding the area occupied by window insets. When
* the app is restricted to a single screen in a multiple-screen
* environment, {@code screenWidthDp} is the width of the screen on which
* the app is displayed excluding window insets.
*
* If the app targets {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or after,
* it is the same as {@link android.view.WindowMetrics}, but is expressed rounded to the nearest
* dp rather than px.
*
* Otherwise, differs from {@link android.view.WindowMetrics} by not including
* window insets in the width measurement and by expressing the measurement
* in dp rather than px. Use {@code screenWidthDp} to obtain the width of
* the display area available to an app or embedded activity excluding the
* area occupied by window insets.
*/
public int screenWidthDp;
/**
* Default value for {@link #screenHeightDp} indicating that no width
* has been specified.
*/
public static final int SCREEN_HEIGHT_DP_UNDEFINED = 0;
/**
* The height of the available screen space in dp units.
*
*
*
* Use {@link android.view.WindowMetrics#getBounds()} to always obtain the vertical
* display area available to an app or embedded activity including the area
* occupied by window insets. A version of the API is also available for use on older platforms
* through {@link androidx.window.layout.WindowMetrics}.
*
* Corresponds to the
*
* available height resource qualifier. Defaults to
* {@link #SCREEN_HEIGHT_DP_UNDEFINED} if no height is specified.
*
* In multi-window mode, equals the height of the available display area
* of the app window, not the available display area of the device screen
* (for example, when apps are displayed one above another in split-screen
* mode in portrait orientation).
*
* For embedded activities, equals the height of the individual
* activities, not the height of the app window or the device screen.
*
* In multiple-screen scenarios, the height measurement can span screens.
* For example, if the app is spanning both screens of a dual-screen device
* rotated 90 degrees (one screen above the other), {@code screenHeightDp}
* represents the height of both screens excluding the area occupied by
* window insets. When the app is restricted to a single screen in a
* multiple-screen environment, {@code screenHeightDp} is the height of the
* screen on which the app is displayed excluding window insets.
*
* If the app targets {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or after,
* it is the same as {@link android.view.WindowMetrics}, but is expressed rounded to the nearest
* dp rather than px.
*
* Otherwise, differs from {@link android.view.WindowMetrics} by not including
* window insets in the height measurement and by expressing the measurement
* in dp rather than px. Use {@code screenHeightDp} to obtain the height of
* the display area available to an app or embedded activity excluding the
* area occupied by window insets.
*/
public int screenHeightDp;
/**
* Default value for {@link #smallestScreenWidthDp} indicating that no width
* has been specified.
*/
public static final int SMALLEST_SCREEN_WIDTH_DP_UNDEFINED = 0;
/**
* The smallest screen size an application will see in normal operation.
* Corresponds to the
*
* smallest width resource qualifier. This is the smallest value of
* {@link #screenWidthDp} and {@link #screenHeightDp} in both portrait and
* landscape orientations. Defaults to
* {@link #SMALLEST_SCREEN_WIDTH_DP_UNDEFINED} if no width is specified.
*/
public int smallestScreenWidthDp;
/**
* Default value for {@link #densityDpi} indicating that no width
* has been specified.
*/
public static final int DENSITY_DPI_UNDEFINED = 0;
/**
* Value for {@link #densityDpi} for resources that scale to any density (vector drawables).
* {@hide}
*/
public static final int DENSITY_DPI_ANY = 0xfffe;
/**
* Value for {@link #densityDpi} for resources that are not meant to be scaled.
* {@hide}
*/
public static final int DENSITY_DPI_NONE = 0xffff;
/**
* The target screen density being rendered to,
* corresponding to
* density
* resource qualifier. Set to
* {@link #DENSITY_DPI_UNDEFINED} if no density is specified.
*/
public int densityDpi;
/** @hide Hack to get this information from WM to app running in compat mode. */
public int compatScreenWidthDp;
/** @hide Hack to get this information from WM to app running in compat mode. */
public int compatScreenHeightDp;
/** @hide Hack to get this information from WM to app running in compat mode. */
public int compatSmallestScreenWidthDp;
/**
* An undefined assetsSeq. This will not override an existing assetsSeq.
* @hide
*/
public static final int ASSETS_SEQ_UNDEFINED = 0;
/**
* Internal counter that allows us to piggyback off the configuration change mechanism to
* signal to apps that the the assets for an Application have changed. A difference in these
* between two Configurations will yield a diff flag of
* {@link ActivityInfo#CONFIG_ASSETS_PATHS}.
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@TestApi
public int assetsSeq;
/**
* @hide Internal book-keeping.
*/
@UnsupportedAppUsage
public int seq;
/** @hide */
@IntDef(flag = true, prefix = { "NATIVE_CONFIG_" }, value = {
NATIVE_CONFIG_MCC,
NATIVE_CONFIG_MNC,
NATIVE_CONFIG_LOCALE,
NATIVE_CONFIG_TOUCHSCREEN,
NATIVE_CONFIG_KEYBOARD,
NATIVE_CONFIG_KEYBOARD_HIDDEN,
NATIVE_CONFIG_NAVIGATION,
NATIVE_CONFIG_ORIENTATION,
NATIVE_CONFIG_DENSITY,
NATIVE_CONFIG_SCREEN_SIZE,
NATIVE_CONFIG_VERSION,
NATIVE_CONFIG_SCREEN_LAYOUT,
NATIVE_CONFIG_UI_MODE,
NATIVE_CONFIG_SMALLEST_SCREEN_SIZE,
NATIVE_CONFIG_LAYOUTDIR,
NATIVE_CONFIG_COLOR_MODE,
NATIVE_CONFIG_GRAMMATICAL_GENDER,
})
@Retention(RetentionPolicy.SOURCE)
public @interface NativeConfig {}
/** @hide Native-specific bit mask for MCC config; DO NOT USE UNLESS YOU ARE SURE. */
public static final int NATIVE_CONFIG_MCC = 0x0001;
/** @hide Native-specific bit mask for MNC config; DO NOT USE UNLESS YOU ARE SURE. */
public static final int NATIVE_CONFIG_MNC = 0x0002;
/** @hide Native-specific bit mask for LOCALE config; DO NOT USE UNLESS YOU ARE SURE. */
public static final int NATIVE_CONFIG_LOCALE = 0x0004;
/** @hide Native-specific bit mask for TOUCHSCREEN config; DO NOT USE UNLESS YOU ARE SURE. */
public static final int NATIVE_CONFIG_TOUCHSCREEN = 0x0008;
/** @hide Native-specific bit mask for KEYBOARD config; DO NOT USE UNLESS YOU ARE SURE. */
public static final int NATIVE_CONFIG_KEYBOARD = 0x0010;
/** @hide Native-specific bit mask for KEYBOARD_HIDDEN config; DO NOT USE UNLESS YOU
* ARE SURE. */
public static final int NATIVE_CONFIG_KEYBOARD_HIDDEN = 0x0020;
/** @hide Native-specific bit mask for NAVIGATION config; DO NOT USE UNLESS YOU ARE SURE. */
public static final int NATIVE_CONFIG_NAVIGATION = 0x0040;
/** @hide Native-specific bit mask for ORIENTATION config; DO NOT USE UNLESS YOU ARE SURE. */
public static final int NATIVE_CONFIG_ORIENTATION = 0x0080;
/** @hide Native-specific bit mask for DENSITY config; DO NOT USE UNLESS YOU ARE SURE. */
public static final int NATIVE_CONFIG_DENSITY = 0x0100;
/** @hide Native-specific bit mask for SCREEN_SIZE config; DO NOT USE UNLESS YOU ARE SURE. */
public static final int NATIVE_CONFIG_SCREEN_SIZE = 0x0200;
/** @hide Native-specific bit mask for VERSION config; DO NOT USE UNLESS YOU ARE SURE. */
public static final int NATIVE_CONFIG_VERSION = 0x0400;
/** @hide Native-specific bit mask for SCREEN_LAYOUT config; DO NOT USE UNLESS YOU ARE SURE. */
public static final int NATIVE_CONFIG_SCREEN_LAYOUT = 0x0800;
/** @hide Native-specific bit mask for UI_MODE config; DO NOT USE UNLESS YOU ARE SURE. */
public static final int NATIVE_CONFIG_UI_MODE = 0x1000;
/** @hide Native-specific bit mask for SMALLEST_SCREEN_SIZE config; DO NOT USE UNLESS YOU
* ARE SURE. */
public static final int NATIVE_CONFIG_SMALLEST_SCREEN_SIZE = 0x2000;
/** @hide Native-specific bit mask for LAYOUTDIR config ; DO NOT USE UNLESS YOU ARE SURE.*/
public static final int NATIVE_CONFIG_LAYOUTDIR = 0x4000;
/** @hide Native-specific bit mask for COLOR_MODE config ; DO NOT USE UNLESS YOU ARE SURE.*/
public static final int NATIVE_CONFIG_COLOR_MODE = 0x10000;
/** @hide Native-specific bit mask for GRAMMATICAL_GENDER config; DO NOT USE UNLESS YOU
* ARE SURE.*/
public static final int NATIVE_CONFIG_GRAMMATICAL_GENDER = 0x20000;
/**
* Construct an invalid Configuration. This state is only suitable for constructing a
* Configuration delta that will be applied to some valid Configuration object. In order to
* create a valid standalone Configuration, you must call {@link #setToDefaults}. Example:
* Configuration validConfig = new Configuration();
* validConfig.setToDefaults();
*
* Configuration deltaOnlyConfig = new Configuration();
* deltaOnlyConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
*
* validConfig.updateFrom(deltaOnlyConfig);
*
*/
public Configuration() {
unset();
}
/**
* Makes a deep copy suitable for modification.
*/
public Configuration(Configuration o) {
setTo(o);
}
/* This brings mLocaleList in sync with locale in case a user of the older API who doesn't know
* about setLocales() has changed locale directly. */
private void fixUpLocaleList() {
if ((locale == null && !mLocaleList.isEmpty()) ||
(locale != null && !locale.equals(mLocaleList.get(0)))) {
mLocaleList = locale == null ? LocaleList.getEmptyLocaleList() : new LocaleList(locale);
}
}
/**
* Sets the fields in this object to those in the given Configuration.
*
* @param o The Configuration object used to set the values of this Configuration's fields.
*/
public void setTo(Configuration o) {
fontScale = o.fontScale;
mcc = o.mcc;
mnc = o.mnc;
if (o.locale == null) {
locale = null;
} else if (!o.locale.equals(locale)) {
// Only clone a new Locale instance if we need to: the clone() is
// both CPU and GC intensive.
locale = (Locale) o.locale.clone();
}
o.fixUpLocaleList();
mLocaleList = o.mLocaleList;
mGrammaticalGender = o.mGrammaticalGender;
userSetLocale = o.userSetLocale;
touchscreen = o.touchscreen;
keyboard = o.keyboard;
keyboardHidden = o.keyboardHidden;
hardKeyboardHidden = o.hardKeyboardHidden;
navigation = o.navigation;
navigationHidden = o.navigationHidden;
orientation = o.orientation;
screenLayout = o.screenLayout;
colorMode = o.colorMode;
uiMode = o.uiMode;
screenWidthDp = o.screenWidthDp;
screenHeightDp = o.screenHeightDp;
smallestScreenWidthDp = o.smallestScreenWidthDp;
densityDpi = o.densityDpi;
compatScreenWidthDp = o.compatScreenWidthDp;
compatScreenHeightDp = o.compatScreenHeightDp;
compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp;
assetsSeq = o.assetsSeq;
seq = o.seq;
windowConfiguration.setTo(o.windowConfiguration);
fontWeightAdjustment = o.fontWeightAdjustment;
}
public String toString() {
StringBuilder sb = new StringBuilder(128);
sb.append("{");
sb.append(fontScale);
sb.append(" ");
if (mcc != 0) {
sb.append(mcc);
sb.append("mcc");
} else {
sb.append("?mcc");
}
if (mnc != MNC_ZERO) {
sb.append(mnc);
sb.append("mnc");
} else {
sb.append("?mnc");
}
fixUpLocaleList();
if (!mLocaleList.isEmpty()) {
sb.append(" ");
sb.append(mLocaleList);
} else {
sb.append(" ?localeList");
}
if (mGrammaticalGender > 0) {
switch (mGrammaticalGender) {
case GRAMMATICAL_GENDER_NEUTRAL: sb.append(" neuter"); break;
case GRAMMATICAL_GENDER_FEMININE: sb.append(" feminine"); break;
case GRAMMATICAL_GENDER_MASCULINE: sb.append(" masculine"); break;
default: sb.append(" ?grgend"); break;
}
}
int layoutDir = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK);
switch (layoutDir) {
case SCREENLAYOUT_LAYOUTDIR_UNDEFINED: sb.append(" ?layoutDir"); break;
case SCREENLAYOUT_LAYOUTDIR_LTR: sb.append(" ldltr"); break;
case SCREENLAYOUT_LAYOUTDIR_RTL: sb.append(" ldrtl"); break;
default: sb.append(" layoutDir=");
sb.append(layoutDir >> SCREENLAYOUT_LAYOUTDIR_SHIFT); break;
}
if (smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
sb.append(" sw"); sb.append(smallestScreenWidthDp); sb.append("dp");
} else {
sb.append(" ?swdp");
}
if (screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) {
sb.append(" w"); sb.append(screenWidthDp); sb.append("dp");
} else {
sb.append(" ?wdp");
}
if (screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) {
sb.append(" h"); sb.append(screenHeightDp); sb.append("dp");
} else {
sb.append(" ?hdp");
}
if (densityDpi != DENSITY_DPI_UNDEFINED) {
sb.append(" "); sb.append(densityDpi); sb.append("dpi");
} else {
sb.append(" ?density");
}
switch ((screenLayout&SCREENLAYOUT_SIZE_MASK)) {
case SCREENLAYOUT_SIZE_UNDEFINED: sb.append(" ?lsize"); break;
case SCREENLAYOUT_SIZE_SMALL: sb.append(" smll"); break;
case SCREENLAYOUT_SIZE_NORMAL: sb.append(" nrml"); break;
case SCREENLAYOUT_SIZE_LARGE: sb.append(" lrg"); break;
case SCREENLAYOUT_SIZE_XLARGE: sb.append(" xlrg"); break;
default: sb.append(" layoutSize=");
sb.append(screenLayout&SCREENLAYOUT_SIZE_MASK); break;
}
switch ((screenLayout&SCREENLAYOUT_LONG_MASK)) {
case SCREENLAYOUT_LONG_UNDEFINED: sb.append(" ?long"); break;
case SCREENLAYOUT_LONG_NO: /* not-long is not interesting to print */ break;
case SCREENLAYOUT_LONG_YES: sb.append(" long"); break;
default: sb.append(" layoutLong=");
sb.append(screenLayout&SCREENLAYOUT_LONG_MASK); break;
}
switch ((colorMode &COLOR_MODE_HDR_MASK)) {
case COLOR_MODE_HDR_UNDEFINED: sb.append(" ?ldr"); break; // most likely not HDR
case COLOR_MODE_HDR_NO: /* ldr is not interesting to print */ break;
case COLOR_MODE_HDR_YES: sb.append(" hdr"); break;
default: sb.append(" dynamicRange=");
sb.append(colorMode &COLOR_MODE_HDR_MASK); break;
}
switch ((colorMode &COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) {
case COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED: sb.append(" ?wideColorGamut"); break;
case COLOR_MODE_WIDE_COLOR_GAMUT_NO: /* not wide is not interesting to print */ break;
case COLOR_MODE_WIDE_COLOR_GAMUT_YES: sb.append(" widecg"); break;
default: sb.append(" wideColorGamut=");
sb.append(colorMode &COLOR_MODE_WIDE_COLOR_GAMUT_MASK); break;
}
switch (orientation) {
case ORIENTATION_UNDEFINED: sb.append(" ?orien"); break;
case ORIENTATION_LANDSCAPE: sb.append(" land"); break;
case ORIENTATION_PORTRAIT: sb.append(" port"); break;
default: sb.append(" orien="); sb.append(orientation); break;
}
switch ((uiMode&UI_MODE_TYPE_MASK)) {
case UI_MODE_TYPE_UNDEFINED: sb.append(" ?uimode"); break;
case UI_MODE_TYPE_NORMAL: /* normal is not interesting to print */ break;
case UI_MODE_TYPE_DESK: sb.append(" desk"); break;
case UI_MODE_TYPE_CAR: sb.append(" car"); break;
case UI_MODE_TYPE_TELEVISION: sb.append(" television"); break;
case UI_MODE_TYPE_APPLIANCE: sb.append(" appliance"); break;
case UI_MODE_TYPE_WATCH: sb.append(" watch"); break;
case UI_MODE_TYPE_VR_HEADSET: sb.append(" vrheadset"); break;
default: sb.append(" uimode="); sb.append(uiMode&UI_MODE_TYPE_MASK); break;
}
switch ((uiMode&UI_MODE_NIGHT_MASK)) {
case UI_MODE_NIGHT_UNDEFINED: sb.append(" ?night"); break;
case UI_MODE_NIGHT_NO: /* not-night is not interesting to print */ break;
case UI_MODE_NIGHT_YES: sb.append(" night"); break;
default: sb.append(" night="); sb.append(uiMode&UI_MODE_NIGHT_MASK); break;
}
switch (touchscreen) {
case TOUCHSCREEN_UNDEFINED: sb.append(" ?touch"); break;
case TOUCHSCREEN_NOTOUCH: sb.append(" -touch"); break;
case TOUCHSCREEN_STYLUS: sb.append(" stylus"); break;
case TOUCHSCREEN_FINGER: sb.append(" finger"); break;
default: sb.append(" touch="); sb.append(touchscreen); break;
}
switch (keyboard) {
case KEYBOARD_UNDEFINED: sb.append(" ?keyb"); break;
case KEYBOARD_NOKEYS: sb.append(" -keyb"); break;
case KEYBOARD_QWERTY: sb.append(" qwerty"); break;
case KEYBOARD_12KEY: sb.append(" 12key"); break;
default: sb.append(" keys="); sb.append(keyboard); break;
}
switch (keyboardHidden) {
case KEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break;
case KEYBOARDHIDDEN_NO: sb.append("/v"); break;
case KEYBOARDHIDDEN_YES: sb.append("/h"); break;
case KEYBOARDHIDDEN_SOFT: sb.append("/s"); break;
default: sb.append("/"); sb.append(keyboardHidden); break;
}
switch (hardKeyboardHidden) {
case HARDKEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break;
case HARDKEYBOARDHIDDEN_NO: sb.append("/v"); break;
case HARDKEYBOARDHIDDEN_YES: sb.append("/h"); break;
default: sb.append("/"); sb.append(hardKeyboardHidden); break;
}
switch (navigation) {
case NAVIGATION_UNDEFINED: sb.append(" ?nav"); break;
case NAVIGATION_NONAV: sb.append(" -nav"); break;
case NAVIGATION_DPAD: sb.append(" dpad"); break;
case NAVIGATION_TRACKBALL: sb.append(" tball"); break;
case NAVIGATION_WHEEL: sb.append(" wheel"); break;
default: sb.append(" nav="); sb.append(navigation); break;
}
switch (navigationHidden) {
case NAVIGATIONHIDDEN_UNDEFINED: sb.append("/?"); break;
case NAVIGATIONHIDDEN_NO: sb.append("/v"); break;
case NAVIGATIONHIDDEN_YES: sb.append("/h"); break;
default: sb.append("/"); sb.append(navigationHidden); break;
}
sb.append(" winConfig="); sb.append(windowConfiguration);
if (assetsSeq != 0) {
sb.append(" as.").append(assetsSeq);
}
if (seq != 0) {
sb.append(" s.").append(seq);
}
if (fontWeightAdjustment != FONT_WEIGHT_ADJUSTMENT_UNDEFINED) {
sb.append(" fontWeightAdjustment=");
sb.append(fontWeightAdjustment);
} else {
sb.append(" ?fontWeightAdjustment");
}
sb.append('}');
return sb.toString();
}
/**
* Write to a protocol buffer output stream.
* Protocol buffer message definition at {@link android.content.ConfigurationProto}
* Has the option to ignore fields that don't need to be persisted to disk.
*
* @param protoOutputStream Stream to write the Configuration object to.
* @param fieldId Field Id of the Configuration as defined in the parent message
* @param persisted Note if this proto will be persisted to disk
* @param critical If true, reduce amount of data written.
* @hide
*/
public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean persisted,
boolean critical) {
final long token = protoOutputStream.start(fieldId);
if (!critical) {
protoOutputStream.write(FONT_SCALE, fontScale);
protoOutputStream.write(MCC, mcc);
protoOutputStream.write(MNC, mnc);
if (mLocaleList != null) {
protoOutputStream.write(LOCALE_LIST, mLocaleList.toLanguageTags());
}
protoOutputStream.write(SCREEN_LAYOUT, screenLayout);
protoOutputStream.write(COLOR_MODE, colorMode);
protoOutputStream.write(TOUCHSCREEN, touchscreen);
protoOutputStream.write(KEYBOARD, keyboard);
protoOutputStream.write(KEYBOARD_HIDDEN, keyboardHidden);
protoOutputStream.write(HARD_KEYBOARD_HIDDEN, hardKeyboardHidden);
protoOutputStream.write(NAVIGATION, navigation);
protoOutputStream.write(NAVIGATION_HIDDEN, navigationHidden);
protoOutputStream.write(UI_MODE, uiMode);
protoOutputStream.write(SMALLEST_SCREEN_WIDTH_DP, smallestScreenWidthDp);
protoOutputStream.write(DENSITY_DPI, densityDpi);
// For persistence, we do not care about window configuration
if (!persisted && windowConfiguration != null) {
windowConfiguration.dumpDebug(protoOutputStream, WINDOW_CONFIGURATION);
}
protoOutputStream.write(FONT_WEIGHT_ADJUSTMENT, fontWeightAdjustment);
}
protoOutputStream.write(ORIENTATION, orientation);
protoOutputStream.write(SCREEN_WIDTH_DP, screenWidthDp);
protoOutputStream.write(SCREEN_HEIGHT_DP, screenHeightDp);
protoOutputStream.write(GRAMMATICAL_GENDER, mGrammaticalGender);
protoOutputStream.end(token);
}
/**
* Write to a protocol buffer output stream.
* Protocol buffer message definition at {@link android.content.ConfigurationProto}
*
* @param protoOutputStream Stream to write the Configuration object to.
* @param fieldId Field Id of the Configuration as defined in the parent message
* @hide
*/
public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId) {
dumpDebug(protoOutputStream, fieldId, false /* persisted */, false /* critical */);
}
/**
* Write to a protocol buffer output stream.
* Protocol buffer message definition at {@link android.content.ConfigurationProto}
*
* @param protoOutputStream Stream to write the Configuration object to.
* @param fieldId Field Id of the Configuration as defined in the parent message
* @param critical If true, reduce amount of data written.
* @hide
*/
public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean critical) {
dumpDebug(protoOutputStream, fieldId, false /* persisted */, critical);
}
/**
* Read from a protocol buffer output stream.
* Protocol buffer message definition at {@link android.content.ConfigurationProto}
*
* @param protoInputStream Stream to read the Configuration object from.
* @param fieldId Field Id of the Configuration as defined in the parent message
* @hide
*/
public void readFromProto(ProtoInputStream protoInputStream, long fieldId) throws IOException {
final long token = protoInputStream.start(fieldId);
final List.equals()
on the input locale and the
* {@link #locale} attribute would return true
if they are not null, but there is
* no guarantee that they would be the same object.
*
* See also the note about layout direction in {@link #setLocales(LocaleList)}.
*
* @param loc The locale. Can be null.
*/
public void setLocale(@Nullable Locale loc) {
setLocales(loc == null ? LocaleList.getEmptyLocaleList() : new LocaleList(loc));
}
/**
* @hide
*
* Clears the locale without changing layout direction.
*/
public void clearLocales() {
mLocaleList = LocaleList.getEmptyLocaleList();
locale = null;
}
/**
* Return the layout direction. Will be either {@link View#LAYOUT_DIRECTION_LTR} or
* {@link View#LAYOUT_DIRECTION_RTL}.
*
* @return Returns {@link View#LAYOUT_DIRECTION_RTL} if the configuration
* is {@link #SCREENLAYOUT_LAYOUTDIR_RTL}, otherwise {@link View#LAYOUT_DIRECTION_LTR}.
*/
public int getLayoutDirection() {
return (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK) == SCREENLAYOUT_LAYOUTDIR_RTL
? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
}
/**
* Set the layout direction from a Locale.
*
* @param loc The Locale. If null will set the layout direction to
* {@link View#LAYOUT_DIRECTION_LTR}. If not null will set it to the layout direction
* corresponding to the Locale.
*
* @see View#LAYOUT_DIRECTION_LTR
* @see View#LAYOUT_DIRECTION_RTL
*/
public void setLayoutDirection(Locale loc) {
// There is a "1" difference between the configuration values for
// layout direction and View constants for layout direction, just add "1".
final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(loc);
screenLayout = (screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK)|
(layoutDirection << SCREENLAYOUT_LAYOUTDIR_SHIFT);
}
private static int getScreenLayoutNoDirection(int screenLayout) {
return screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK;
}
/**
* Return whether the screen has a round shape. Apps may choose to change styling based
* on this property, such as the alignment or layout of text or informational icons.
*
* @return true if the screen is rounded, false otherwise
*/
public boolean isScreenRound() {
return (screenLayout & SCREENLAYOUT_ROUND_MASK) == SCREENLAYOUT_ROUND_YES;
}
/**
* Return whether the screen has a wide color gamut and wide color gamut rendering
* is supported by this device.
*
* When true, it implies the screen is colorspace aware but not
* necessarily color-managed. The final colors may still be changed by the
* screen depending on user settings.
*
* @return true if the screen has a wide color gamut and wide color gamut rendering
* is supported, false otherwise
*/
public boolean isScreenWideColorGamut() {
return (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) == COLOR_MODE_WIDE_COLOR_GAMUT_YES;
}
/**
* Return whether the screen has a high dynamic range.
*
* @return true if the screen has a high dynamic range, false otherwise
*/
public boolean isScreenHdr() {
return (colorMode & COLOR_MODE_HDR_MASK) == COLOR_MODE_HDR_YES;
}
/**
*
* @hide
*/
public static String localesToResourceQualifier(LocaleList locs) {
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < locs.size(); i++) {
final Locale loc = locs.get(i);
final int l = loc.getLanguage().length();
if (l == 0) {
continue;
}
final int s = loc.getScript().length();
final int c = loc.getCountry().length();
final int v = loc.getVariant().length();
// We ignore locale extensions, since they are not supported by AAPT
if (sb.length() != 0) {
sb.append(",");
}
if (l == 2 && s == 0 && (c == 0 || c == 2) && v == 0) {
// Traditional locale format: xx or xx-rYY
sb.append(loc.getLanguage());
if (c == 2) {
sb.append("-r").append(loc.getCountry());
}
} else {
sb.append("b+");
sb.append(loc.getLanguage());
if (s != 0) {
sb.append("+");
sb.append(loc.getScript());
}
if (c != 0) {
sb.append("+");
sb.append(loc.getCountry());
}
if (v != 0) {
sb.append("+");
sb.append(loc.getVariant());
}
}
}
return sb.toString();
}
/**
* Returns a string representation of the configuration that can be parsed
* by build tools (like AAPT), without display metrics included
*
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static String resourceQualifierString(Configuration config) {
return resourceQualifierString(config, null);
}
/**
* Returns a string representation of the configuration that can be parsed
* by build tools (like AAPT).
*
* @hide
*/
public static String resourceQualifierString(Configuration config, DisplayMetrics metrics) {
ArrayListbase
and change
. The
* resulting delta can be used with {@link #updateFrom(Configuration)}.
*
* Caveat: If the any of the Configuration's members becomes undefined, then
* {@link #updateFrom(Configuration)} will treat it as a no-op and not update that member.
*
* This is fine for device configurations as no member is ever undefined.
*/
@NonNull
public static Configuration generateDelta(
@NonNull Configuration base, @NonNull Configuration change) {
final Configuration delta = new Configuration();
if (base.fontScale != change.fontScale) {
delta.fontScale = change.fontScale;
}
if (base.mcc != change.mcc) {
delta.mcc = change.mcc;
}
if (base.mnc != change.mnc) {
delta.mnc = change.mnc;
}
base.fixUpLocaleList();
change.fixUpLocaleList();
if (!base.mLocaleList.equals(change.mLocaleList)) {
delta.mLocaleList = change.mLocaleList;
delta.locale = change.locale;
}
if (base.mGrammaticalGender != change.mGrammaticalGender) {
delta.mGrammaticalGender = change.mGrammaticalGender;
}
if (base.touchscreen != change.touchscreen) {
delta.touchscreen = change.touchscreen;
}
if (base.keyboard != change.keyboard) {
delta.keyboard = change.keyboard;
}
if (base.keyboardHidden != change.keyboardHidden) {
delta.keyboardHidden = change.keyboardHidden;
}
if (base.navigation != change.navigation) {
delta.navigation = change.navigation;
}
if (base.navigationHidden != change.navigationHidden) {
delta.navigationHidden = change.navigationHidden;
}
if (base.orientation != change.orientation) {
delta.orientation = change.orientation;
}
if ((base.screenLayout & SCREENLAYOUT_SIZE_MASK) !=
(change.screenLayout & SCREENLAYOUT_SIZE_MASK)) {
delta.screenLayout |= change.screenLayout & SCREENLAYOUT_SIZE_MASK;
}
if ((base.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK) !=
(change.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) {
delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
}
if ((base.screenLayout & SCREENLAYOUT_LONG_MASK) !=
(change.screenLayout & SCREENLAYOUT_LONG_MASK)) {
delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LONG_MASK;
}
if ((base.screenLayout & SCREENLAYOUT_ROUND_MASK) !=
(change.screenLayout & SCREENLAYOUT_ROUND_MASK)) {
delta.screenLayout |= change.screenLayout & SCREENLAYOUT_ROUND_MASK;
}
if ((base.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) !=
(change.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) {
delta.colorMode |= change.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK;
}
if ((base.colorMode & COLOR_MODE_HDR_MASK) !=
(change.colorMode & COLOR_MODE_HDR_MASK)) {
delta.colorMode |= change.colorMode & COLOR_MODE_HDR_MASK;
}
if ((base.uiMode & UI_MODE_TYPE_MASK) != (change.uiMode & UI_MODE_TYPE_MASK)) {
delta.uiMode |= change.uiMode & UI_MODE_TYPE_MASK;
}
if ((base.uiMode & UI_MODE_NIGHT_MASK) != (change.uiMode & UI_MODE_NIGHT_MASK)) {
delta.uiMode |= change.uiMode & UI_MODE_NIGHT_MASK;
}
if (base.screenWidthDp != change.screenWidthDp) {
delta.screenWidthDp = change.screenWidthDp;
}
if (base.screenHeightDp != change.screenHeightDp) {
delta.screenHeightDp = change.screenHeightDp;
}
if (base.smallestScreenWidthDp != change.smallestScreenWidthDp) {
delta.smallestScreenWidthDp = change.smallestScreenWidthDp;
}
if (base.densityDpi != change.densityDpi) {
delta.densityDpi = change.densityDpi;
}
if (base.assetsSeq != change.assetsSeq) {
delta.assetsSeq = change.assetsSeq;
}
if (!base.windowConfiguration.equals(change.windowConfiguration)) {
delta.windowConfiguration.setTo(change.windowConfiguration);
}
if (base.fontWeightAdjustment != change.fontWeightAdjustment) {
delta.fontWeightAdjustment = change.fontWeightAdjustment;
}
return delta;
}
private static final String XML_ATTR_FONT_SCALE = "fs";
private static final String XML_ATTR_MCC = "mcc";
private static final String XML_ATTR_MNC = "mnc";
private static final String XML_ATTR_LOCALES = "locales";
private static final String XML_ATTR_TOUCHSCREEN = "touch";
private static final String XML_ATTR_KEYBOARD = "key";
private static final String XML_ATTR_KEYBOARD_HIDDEN = "keyHid";
private static final String XML_ATTR_HARD_KEYBOARD_HIDDEN = "hardKeyHid";
private static final String XML_ATTR_NAVIGATION = "nav";
private static final String XML_ATTR_NAVIGATION_HIDDEN = "navHid";
private static final String XML_ATTR_ORIENTATION = "ori";
private static final String XML_ATTR_ROTATION = "rot";
private static final String XML_ATTR_SCREEN_LAYOUT = "scrLay";
private static final String XML_ATTR_COLOR_MODE = "clrMod";
private static final String XML_ATTR_UI_MODE = "ui";
private static final String XML_ATTR_SCREEN_WIDTH = "width";
private static final String XML_ATTR_SCREEN_HEIGHT = "height";
private static final String XML_ATTR_SMALLEST_WIDTH = "sw";
private static final String XML_ATTR_DENSITY = "density";
private static final String XML_ATTR_APP_BOUNDS = "app_bounds";
private static final String XML_ATTR_FONT_WEIGHT_ADJUSTMENT = "fontWeightAdjustment";
private static final String XML_ATTR_GRAMMATICAL_GENDER = "grammaticalGender";
/**
* Reads the attributes corresponding to Configuration member fields from the Xml parser.
* The parser is expected to be on a tag which has Configuration attributes.
*
* @param parser The Xml parser from which to read attributes.
* @param configOut The Configuration to populate from the Xml attributes.
* {@hide}
*/
public static void readXmlAttrs(XmlPullParser parser, Configuration configOut)
throws XmlPullParserException, IOException {
configOut.fontScale = Float.intBitsToFloat(
XmlUtils.readIntAttribute(parser, XML_ATTR_FONT_SCALE, 0));
configOut.mcc = XmlUtils.readIntAttribute(parser, XML_ATTR_MCC, 0);
configOut.mnc = XmlUtils.readIntAttribute(parser, XML_ATTR_MNC, 0);
final String localesStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALES);
configOut.mLocaleList = LocaleList.forLanguageTags(localesStr);
configOut.locale = configOut.mLocaleList.get(0);
configOut.touchscreen = XmlUtils.readIntAttribute(parser, XML_ATTR_TOUCHSCREEN,
TOUCHSCREEN_UNDEFINED);
configOut.keyboard = XmlUtils.readIntAttribute(parser, XML_ATTR_KEYBOARD,
KEYBOARD_UNDEFINED);
configOut.keyboardHidden = XmlUtils.readIntAttribute(parser, XML_ATTR_KEYBOARD_HIDDEN,
KEYBOARDHIDDEN_UNDEFINED);
configOut.hardKeyboardHidden =
XmlUtils.readIntAttribute(parser, XML_ATTR_HARD_KEYBOARD_HIDDEN,
HARDKEYBOARDHIDDEN_UNDEFINED);
configOut.navigation = XmlUtils.readIntAttribute(parser, XML_ATTR_NAVIGATION,
NAVIGATION_UNDEFINED);
configOut.navigationHidden = XmlUtils.readIntAttribute(parser, XML_ATTR_NAVIGATION_HIDDEN,
NAVIGATIONHIDDEN_UNDEFINED);
configOut.orientation = XmlUtils.readIntAttribute(parser, XML_ATTR_ORIENTATION,
ORIENTATION_UNDEFINED);
configOut.screenLayout = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_LAYOUT,
SCREENLAYOUT_UNDEFINED);
configOut.colorMode = XmlUtils.readIntAttribute(parser, XML_ATTR_COLOR_MODE,
COLOR_MODE_UNDEFINED);
configOut.uiMode = XmlUtils.readIntAttribute(parser, XML_ATTR_UI_MODE, 0);
configOut.screenWidthDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_WIDTH,
SCREEN_WIDTH_DP_UNDEFINED);
configOut.screenHeightDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_HEIGHT,
SCREEN_HEIGHT_DP_UNDEFINED);
configOut.smallestScreenWidthDp =
XmlUtils.readIntAttribute(parser, XML_ATTR_SMALLEST_WIDTH,
SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
configOut.densityDpi = XmlUtils.readIntAttribute(parser, XML_ATTR_DENSITY,
DENSITY_DPI_UNDEFINED);
configOut.fontWeightAdjustment = XmlUtils.readIntAttribute(parser,
XML_ATTR_FONT_WEIGHT_ADJUSTMENT, FONT_WEIGHT_ADJUSTMENT_UNDEFINED);
configOut.mGrammaticalGender = XmlUtils.readIntAttribute(parser,
XML_ATTR_GRAMMATICAL_GENDER, GRAMMATICAL_GENDER_UNDEFINED);
// For persistence, we don't care about assetsSeq and WindowConfiguration, so do not read it
// out.
}
}