Reland "Pass all preferred locales to AssetManager"

This reverts commit cc6ff3876e395040748627353b7384e49d90e4f9.

Reason for revert: Fixed the tests in a separate change

Test: ran the previously failing tests in ab
Change-Id: I588d563375388ab1030c9de2072efe865286425c
diff --git a/core/java/android/app/LocaleConfig.java b/core/java/android/app/LocaleConfig.java
index 729e555..0857c96 100644
--- a/core/java/android/app/LocaleConfig.java
+++ b/core/java/android/app/LocaleConfig.java
@@ -40,7 +40,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Set;
@@ -195,7 +195,8 @@
         XmlUtils.beginDocument(parser, TAG_LOCALE_CONFIG);
         int outerDepth = parser.getDepth();
         AttributeSet attrs = Xml.asAttributeSet(parser);
-        Set<String> localeNames = new HashSet<String>();
+        // LinkedHashSet to preserve insertion order
+        Set<String> localeNames = new LinkedHashSet<>();
         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
             if (TAG_LOCALE.equals(parser.getName())) {
                 final TypedArray attributes = res.obtainAttributes(
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 048289f..508eeed 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1456,8 +1456,8 @@
 
     private static AssetManager newConfiguredAssetManager() {
         AssetManager assetManager = new AssetManager();
-        assetManager.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                Build.VERSION.RESOURCES_SDK_INT);
+        assetManager.setConfiguration(0, 0, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, Build.VERSION.RESOURCES_SDK_INT);
         return assetManager;
     }
 
@@ -9011,8 +9011,8 @@
             }
 
             AssetManager assets = new AssetManager();
-            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                    Build.VERSION.RESOURCES_SDK_INT);
+            assets.setConfiguration(0, 0, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    0, 0, 0, Build.VERSION.RESOURCES_SDK_INT);
             assets.setApkAssets(apkAssets, false /*invalidateCaches*/);
 
             mCachedAssetManager = assets;
@@ -9086,8 +9086,8 @@
 
         private static AssetManager createAssetManagerWithAssets(ApkAssets[] apkAssets) {
             final AssetManager assets = new AssetManager();
-            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                    Build.VERSION.RESOURCES_SDK_INT);
+            assets.setConfiguration(0, 0, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    0, 0, 0, Build.VERSION.RESOURCES_SDK_INT);
             assets.setApkAssets(apkAssets, false /*invalidateCaches*/);
             return assets;
         }
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 0f284f4..c9ad251 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -1478,9 +1478,13 @@
             int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp,
             int screenHeightDp, int screenLayout, int uiMode, int colorMode, int grammaticalGender,
             int majorVersion) {
-        synchronized (this) {
-            ensureValidLocked();
-            nativeSetConfiguration(mObject, mcc, mnc, locale, orientation, touchscreen, density,
+        if (locale != null) {
+            setConfiguration(mcc, mnc, null, new String[]{locale}, orientation, touchscreen,
+                    density, keyboard, keyboardHidden, navigation, screenWidth, screenHeight,
+                    smallestScreenWidthDp, screenWidthDp, screenHeightDp, screenLayout, uiMode,
+                    colorMode, grammaticalGender, majorVersion);
+        } else {
+            setConfiguration(mcc, mnc, null, null, orientation, touchscreen, density,
                     keyboard, keyboardHidden, navigation, screenWidth, screenHeight,
                     smallestScreenWidthDp, screenWidthDp, screenHeightDp, screenLayout, uiMode,
                     colorMode, grammaticalGender, majorVersion);
@@ -1488,6 +1492,25 @@
     }
 
     /**
+     * Change the configuration used when retrieving resources.  Not for use by
+     * applications.
+     * @hide
+     */
+    public void setConfiguration(int mcc, int mnc, String defaultLocale, String[] locales,
+            int orientation, int touchscreen, int density, int keyboard, int keyboardHidden,
+            int navigation, int screenWidth, int screenHeight, int smallestScreenWidthDp,
+            int screenWidthDp, int screenHeightDp, int screenLayout, int uiMode, int colorMode,
+            int grammaticalGender, int majorVersion) {
+        synchronized (this) {
+            ensureValidLocked();
+            nativeSetConfiguration(mObject, mcc, mnc, defaultLocale, locales, orientation,
+                    touchscreen, density, keyboard, keyboardHidden, navigation, screenWidth,
+                    screenHeight, smallestScreenWidthDp, screenWidthDp, screenHeightDp,
+                    screenLayout, uiMode, colorMode, grammaticalGender, majorVersion);
+        }
+    }
+
+    /**
      * @hide
      */
     @UnsupportedAppUsage
@@ -1570,10 +1593,11 @@
     private static native void nativeSetApkAssets(long ptr, @NonNull ApkAssets[] apkAssets,
             boolean invalidateCaches);
     private static native void nativeSetConfiguration(long ptr, int mcc, int mnc,
-            @Nullable String locale, int orientation, int touchscreen, int density, int keyboard,
-            int keyboardHidden, int navigation, int screenWidth, int screenHeight,
-            int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp, int screenLayout,
-            int uiMode, int colorMode, int grammaticalGender, int majorVersion);
+            @Nullable String defaultLocale, @NonNull String[] locales, int orientation,
+            int touchscreen, int density, int keyboard, int keyboardHidden, int navigation,
+            int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp,
+            int screenHeightDp, int screenLayout, int uiMode, int colorMode, int grammaticalGender,
+            int majorVersion);
     private static native @NonNull SparseArray<String> nativeGetAssignedPackageIdentifiers(
             long ptr, boolean includeOverlays, boolean includeLoaders);
 
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 61d5aa6..f2468b5 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -407,14 +407,12 @@
                     mConfiguration.setLocales(locales);
                 }
 
+                String[] selectedLocales = null;
+                String defaultLocale = null;
                 if ((configChanges & ActivityInfo.CONFIG_LOCALE) != 0) {
                     if (locales.size() > 1) {
                         String[] availableLocales;
-
-                        LocaleList localeList = ResourcesManager.getInstance().getLocaleList();
-                        if (!localeList.isEmpty()) {
-                            availableLocales = localeList.toLanguageTags().split(",");
-                        } else {
+                        if (ResourcesManager.getInstance().getLocaleList().isEmpty()) {
                             // The LocaleList has changed. We must query the AssetManager's
                             // available Locales and figure out the best matching Locale in the new
                             // LocaleList.
@@ -426,16 +424,32 @@
                                     availableLocales = null;
                                 }
                             }
-                        }
-                        if (availableLocales != null) {
-                            final Locale bestLocale = locales.getFirstMatchWithEnglishSupported(
-                                    availableLocales);
-                            if (bestLocale != null && bestLocale != locales.get(0)) {
-                                mConfiguration.setLocales(new LocaleList(bestLocale, locales));
+                            if (availableLocales != null) {
+                                final Locale bestLocale = locales.getFirstMatchWithEnglishSupported(
+                                        availableLocales);
+                                if (bestLocale != null) {
+                                    selectedLocales = new String[]{
+                                            adjustLanguageTag(bestLocale.toLanguageTag())};
+                                    if (!bestLocale.equals(locales.get(0))) {
+                                        mConfiguration.setLocales(
+                                                new LocaleList(bestLocale, locales));
+                                    }
+                                }
                             }
+                        } else {
+                            selectedLocales = locales.getIntersection(
+                                    ResourcesManager.getInstance().getLocaleList());
+                            defaultLocale = ResourcesManager.getInstance()
+                                    .getLocaleList().get(0).toLanguageTag();
                         }
                     }
                 }
+                if (selectedLocales == null) {
+                    selectedLocales = new String[locales.size()];
+                    for (int i = 0; i < locales.size(); i++) {
+                        selectedLocales[i] = adjustLanguageTag(locales.get(i).toLanguageTag());
+                    }
+                }
 
                 if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
                     mMetrics.densityDpi = mConfiguration.densityDpi;
@@ -470,7 +484,8 @@
                 }
 
                 mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
-                        adjustLanguageTag(mConfiguration.getLocales().get(0).toLanguageTag()),
+                        defaultLocale,
+                        selectedLocales,
                         mConfiguration.orientation,
                         mConfiguration.touchscreen,
                         mConfiguration.densityDpi, mConfiguration.keyboard,
diff --git a/core/java/android/os/LocaleList.java b/core/java/android/os/LocaleList.java
index b74bb33..82cdd28 100644
--- a/core/java/android/os/LocaleList.java
+++ b/core/java/android/os/LocaleList.java
@@ -30,6 +30,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
 
 /**
@@ -151,6 +152,25 @@
     }
 
     /**
+     * Find the intersection between this LocaleList and another
+     * @return a String array of the Locales in both LocaleLists
+     * {@hide}
+     */
+    @NonNull
+    public String[] getIntersection(@NonNull LocaleList other) {
+        List<String> intersection = new ArrayList<>();
+        for (Locale l1 : mList) {
+            for (Locale l2 : other.mList) {
+                if (matchesLanguageAndScript(l2, l1)) {
+                    intersection.add(l1.toLanguageTag());
+                    break;
+                }
+            }
+        }
+        return intersection.toArray(new String[0]);
+    }
+
+    /**
      * Creates a new {@link LocaleList}.
      *
      * If two or more same locales are passed, the repeated locales will be dropped.
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 979c9e3..1afae29 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -347,14 +347,23 @@
 }
 
 static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
-                                   jstring locale, jint orientation, jint touchscreen, jint density,
-                                   jint keyboard, jint keyboard_hidden, jint navigation,
-                                   jint screen_width, jint screen_height,
-                                   jint smallest_screen_width_dp, jint screen_width_dp,
-                                   jint screen_height_dp, jint screen_layout, jint ui_mode,
-                                   jint color_mode, jint grammatical_gender, jint major_version) {
+                                   jstring default_locale, jobjectArray locales, jint orientation,
+                                   jint touchscreen, jint density, jint keyboard,
+                                   jint keyboard_hidden, jint navigation, jint screen_width,
+                                   jint screen_height, jint smallest_screen_width_dp,
+                                   jint screen_width_dp, jint screen_height_dp, jint screen_layout,
+                                   jint ui_mode, jint color_mode, jint grammatical_gender,
+                                   jint major_version) {
   ATRACE_NAME("AssetManager::SetConfiguration");
 
+  const jsize locale_count = (locales == NULL) ? 0 : env->GetArrayLength(locales);
+
+  // Constants duplicated from Java class android.content.res.Configuration.
+  static const jint kScreenLayoutRoundMask = 0x300;
+  static const jint kScreenLayoutRoundShift = 8;
+
+  std::vector<ResTable_config> configs;
+
   ResTable_config configuration;
   memset(&configuration, 0, sizeof(configuration));
   configuration.mcc = static_cast<uint16_t>(mcc);
@@ -375,25 +384,37 @@
   configuration.colorMode = static_cast<uint8_t>(color_mode);
   configuration.grammaticalInflection = static_cast<uint8_t>(grammatical_gender);
   configuration.sdkVersion = static_cast<uint16_t>(major_version);
-
-  if (locale != nullptr) {
-    ScopedUtfChars locale_utf8(env, locale);
-    CHECK(locale_utf8.c_str() != nullptr);
-    configuration.setBcp47Locale(locale_utf8.c_str());
-  }
-
-  // Constants duplicated from Java class android.content.res.Configuration.
-  static const jint kScreenLayoutRoundMask = 0x300;
-  static const jint kScreenLayoutRoundShift = 8;
-
   // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
   // in C++. We must extract the round qualifier out of the Java screenLayout and put it
   // into screenLayout2.
   configuration.screenLayout2 =
-      static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
+          static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
+
+  if (locale_count > 0) {
+    configs.resize(locale_count, configuration);
+    for (int i = 0; i < locale_count; i++) {
+      jstring locale = (jstring)(env->GetObjectArrayElement(locales, i));
+      ScopedUtfChars locale_utf8(env, locale);
+      CHECK(locale_utf8.c_str() != nullptr);
+      configs[i].setBcp47Locale(locale_utf8.c_str());
+    }
+  } else {
+    configs.push_back(configuration);
+  }
+
+  uint32_t default_locale_int = 0;
+  if (default_locale != nullptr) {
+    ResTable_config config;
+    static_assert(std::is_same_v<decltype(config.locale), decltype(default_locale_int)>);
+    ScopedUtfChars locale_utf8(env, default_locale);
+    CHECK(locale_utf8.c_str() != nullptr);
+    config.setBcp47Locale(locale_utf8.c_str());
+    default_locale_int = config.locale;
+  }
 
   auto assetmanager = LockAndStartAssetManager(ptr);
-  assetmanager->SetConfiguration(configuration);
+  assetmanager->SetConfigurations(configs);
+  assetmanager->SetDefaultLocale(default_locale_int);
 }
 
 static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr,
@@ -1498,94 +1519,97 @@
 
 // JNI registration.
 static const JNINativeMethod gAssetManagerMethods[] = {
-    // AssetManager setup methods.
-    {"nativeCreate", "()J", (void*)NativeCreate},
-    {"nativeDestroy", "(J)V", (void*)NativeDestroy},
-    {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
-    {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIIII)V",
-     (void*)NativeSetConfiguration},
-    {"nativeGetAssignedPackageIdentifiers", "(JZZ)Landroid/util/SparseArray;",
-     (void*)NativeGetAssignedPackageIdentifiers},
+        // AssetManager setup methods.
+        {"nativeCreate", "()J", (void*)NativeCreate},
+        {"nativeDestroy", "(J)V", (void*)NativeDestroy},
+        {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
+        {"nativeSetConfiguration", "(JIILjava/lang/String;[Ljava/lang/String;IIIIIIIIIIIIIIII)V",
+         (void*)NativeSetConfiguration},
+        {"nativeGetAssignedPackageIdentifiers", "(JZZ)Landroid/util/SparseArray;",
+         (void*)NativeGetAssignedPackageIdentifiers},
 
-    // AssetManager file methods.
-    {"nativeContainsAllocatedTable", "(J)Z", (void*)ContainsAllocatedTable},
-    {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
-    {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
-    {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
-     (void*)NativeOpenAssetFd},
-    {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
-    {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
-     (void*)NativeOpenNonAssetFd},
-    {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
-    {"nativeOpenXmlAssetFd", "(JILjava/io/FileDescriptor;)J", (void*)NativeOpenXmlAssetFd},
+        // AssetManager file methods.
+        {"nativeContainsAllocatedTable", "(J)Z", (void*)ContainsAllocatedTable},
+        {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
+        {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
+        {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
+         (void*)NativeOpenAssetFd},
+        {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
+        {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
+         (void*)NativeOpenNonAssetFd},
+        {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
+        {"nativeOpenXmlAssetFd", "(JILjava/io/FileDescriptor;)J", (void*)NativeOpenXmlAssetFd},
 
-    // AssetManager resource methods.
-    {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I", (void*)NativeGetResourceValue},
-    {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
-     (void*)NativeGetResourceBagValue},
-    {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
-    {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
-     (void*)NativeGetResourceStringArray},
-    {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
-    {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
-    {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
-    {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
-    {"nativeGetParentThemeIdentifier", "(JI)I",
-     (void*)NativeGetParentThemeIdentifier},
+        // AssetManager resource methods.
+        {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I",
+         (void*)NativeGetResourceValue},
+        {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
+         (void*)NativeGetResourceBagValue},
+        {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
+        {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
+         (void*)NativeGetResourceStringArray},
+        {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
+        {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
+        {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
+        {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
+        {"nativeGetParentThemeIdentifier", "(JI)I", (void*)NativeGetParentThemeIdentifier},
 
-    // AssetManager resource name/ID methods.
-    {"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
-     (void*)NativeGetResourceIdentifier},
-    {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
-    {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
-    {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
-    {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
-    {"nativeSetResourceResolutionLoggingEnabled", "(JZ)V",
-     (void*) NativeSetResourceResolutionLoggingEnabled},
-    {"nativeGetLastResourceResolution", "(J)Ljava/lang/String;",
-     (void*) NativeGetLastResourceResolution},
-    {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
-    {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
-     (void*)NativeGetSizeConfigurations},
-    {"nativeGetSizeAndUiModeConfigurations", "(J)[Landroid/content/res/Configuration;",
-     (void*)NativeGetSizeAndUiModeConfigurations},
+        // AssetManager resource name/ID methods.
+        {"nativeGetResourceIdentifier",
+         "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
+         (void*)NativeGetResourceIdentifier},
+        {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
+        {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;",
+         (void*)NativeGetResourcePackageName},
+        {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
+        {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
+        {"nativeSetResourceResolutionLoggingEnabled", "(JZ)V",
+         (void*)NativeSetResourceResolutionLoggingEnabled},
+        {"nativeGetLastResourceResolution", "(J)Ljava/lang/String;",
+         (void*)NativeGetLastResourceResolution},
+        {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
+        {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
+         (void*)NativeGetSizeConfigurations},
+        {"nativeGetSizeAndUiModeConfigurations", "(J)[Landroid/content/res/Configuration;",
+         (void*)NativeGetSizeAndUiModeConfigurations},
 
-    // Style attribute related methods.
-    {"nativeAttributeResolutionStack", "(JJIII)[I", (void*)NativeAttributeResolutionStack},
-    {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
-    {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
-    {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
+        // Style attribute related methods.
+        {"nativeAttributeResolutionStack", "(JJIII)[I", (void*)NativeAttributeResolutionStack},
+        {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
+        {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
+        {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
 
-    // Theme related methods.
-    {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
-    {"nativeGetThemeFreeFunction", "()J", (void*)NativeGetThemeFreeFunction},
-    {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
-    {"nativeThemeRebase", "(JJ[I[ZI)V", (void*)NativeThemeRebase},
+        // Theme related methods.
+        {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
+        {"nativeGetThemeFreeFunction", "()J", (void*)NativeGetThemeFreeFunction},
+        {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
+        {"nativeThemeRebase", "(JJ[I[ZI)V", (void*)NativeThemeRebase},
 
-    {"nativeThemeCopy", "(JJJJ)V", (void*)NativeThemeCopy},
-    {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
-     (void*)NativeThemeGetAttributeValue},
-    {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
-    {"nativeThemeGetChangingConfigurations", "(J)I", (void*)NativeThemeGetChangingConfigurations},
+        {"nativeThemeCopy", "(JJJJ)V", (void*)NativeThemeCopy},
+        {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
+         (void*)NativeThemeGetAttributeValue},
+        {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
+        {"nativeThemeGetChangingConfigurations", "(J)I",
+         (void*)NativeThemeGetChangingConfigurations},
 
-    // AssetInputStream methods.
-    {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
-    {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
-    {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
-    {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
-    {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
-    {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
+        // AssetInputStream methods.
+        {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
+        {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
+        {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
+        {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
+        {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
+        {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
 
-    // System/idmap related methods.
-    {"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;",
-     (void*)NativeGetOverlayableMap},
-    {"nativeGetOverlayablesToString", "(JLjava/lang/String;)Ljava/lang/String;",
-     (void*)NativeGetOverlayablesToString},
+        // System/idmap related methods.
+        {"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;",
+         (void*)NativeGetOverlayableMap},
+        {"nativeGetOverlayablesToString", "(JLjava/lang/String;)Ljava/lang/String;",
+         (void*)NativeGetOverlayablesToString},
 
-    // Global management/debug methods.
-    {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
-    {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
-    {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
+        // Global management/debug methods.
+        {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
+        {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
+        {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
 };
 
 int register_android_content_AssetManager(JNIEnv* env) {
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index e3f0c8f..6a955bc 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -91,12 +91,17 @@
   StringPoolRef entry_string_ref;
 };
 
-AssetManager2::AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration)
-    : configuration_(configuration) {
+AssetManager2::AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration) {
+  configurations_.push_back(configuration);
+
   // Don't invalidate caches here as there's nothing cached yet.
   SetApkAssets(apk_assets, false);
 }
 
+AssetManager2::AssetManager2() {
+  configurations_.resize(1);
+}
+
 bool AssetManager2::SetApkAssets(ApkAssetsList apk_assets, bool invalidate_caches) {
   BuildDynamicRefTable(apk_assets);
   RebuildFilterList();
@@ -421,9 +426,16 @@
   return false;
 }
 
-void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
-  const int diff = configuration_.diff(configuration);
-  configuration_ = configuration;
+void AssetManager2::SetConfigurations(std::vector<ResTable_config> configurations) {
+  int diff = 0;
+  if (configurations_.size() != configurations.size()) {
+    diff = -1;
+  } else {
+    for (int i = 0; i < configurations_.size(); i++) {
+      diff |= configurations_[i].diff(configurations[i]);
+    }
+  }
+  configurations_ = std::move(configurations);
 
   if (diff) {
     RebuildFilterList();
@@ -620,16 +632,6 @@
 
   auto op = StartOperation();
 
-  // Might use this if density_override != 0.
-  ResTable_config density_override_config;
-
-  // Select our configuration or generate a density override configuration.
-  const ResTable_config* desired_config = &configuration_;
-  if (density_override != 0 && density_override != configuration_.density) {
-    density_override_config = configuration_;
-    density_override_config.density = density_override;
-    desired_config = &density_override_config;
-  }
 
   // Retrieve the package group from the package id of the resource id.
   if (UNLIKELY(!is_valid_resid(resid))) {
@@ -648,119 +650,160 @@
   }
 
   const PackageGroup& package_group = package_groups_[package_idx];
-  auto result = FindEntryInternal(package_group, type_idx, entry_idx, *desired_config,
-                                  stop_at_first_match, ignore_configuration);
-  if (UNLIKELY(!result.has_value())) {
-    return base::unexpected(result.error());
-  }
+  std::optional<FindEntryResult> final_result;
+  bool final_has_locale = false;
+  bool final_overlaid = false;
+  for (auto & config : configurations_) {
+    // Might use this if density_override != 0.
+    ResTable_config density_override_config;
 
-  bool overlaid = false;
-  if (!stop_at_first_match && !ignore_configuration) {
-    const auto& assets = GetApkAssets(result->cookie);
-    if (!assets) {
-      ALOGE("Found expired ApkAssets #%d for resource ID 0x%08x.", result->cookie, resid);
-      return base::unexpected(std::nullopt);
+    // Select our configuration or generate a density override configuration.
+    const ResTable_config* desired_config = &config;
+    if (density_override != 0 && density_override != config.density) {
+      density_override_config = config;
+      density_override_config.density = density_override;
+      desired_config = &density_override_config;
     }
-    if (!assets->IsLoader()) {
-      for (const auto& id_map : package_group.overlays_) {
-        auto overlay_entry = id_map.overlay_res_maps_.Lookup(resid);
-        if (!overlay_entry) {
-          // No id map entry exists for this target resource.
-          continue;
-        }
-        if (overlay_entry.IsInlineValue()) {
-          // The target resource is overlaid by an inline value not represented by a resource.
-          ConfigDescription best_frro_config;
-          Res_value best_frro_value;
-          bool frro_found = false;
-          for( const auto& [config, value] : overlay_entry.GetInlineValue()) {
-            if ((!frro_found || config.isBetterThan(best_frro_config, desired_config))
-                && config.match(*desired_config)) {
-              frro_found = true;
-              best_frro_config = config;
-              best_frro_value = value;
-            }
-          }
-          if (!frro_found) {
+
+    auto result = FindEntryInternal(package_group, type_idx, entry_idx, *desired_config,
+                                    stop_at_first_match, ignore_configuration);
+    if (UNLIKELY(!result.has_value())) {
+      return base::unexpected(result.error());
+    }
+    bool overlaid = false;
+    if (!stop_at_first_match && !ignore_configuration) {
+      const auto& assets = GetApkAssets(result->cookie);
+      if (!assets) {
+        ALOGE("Found expired ApkAssets #%d for resource ID 0x%08x.", result->cookie, resid);
+        return base::unexpected(std::nullopt);
+      }
+      if (!assets->IsLoader()) {
+        for (const auto& id_map : package_group.overlays_) {
+          auto overlay_entry = id_map.overlay_res_maps_.Lookup(resid);
+          if (!overlay_entry) {
+            // No id map entry exists for this target resource.
             continue;
           }
-          result->entry = best_frro_value;
+          if (overlay_entry.IsInlineValue()) {
+            // The target resource is overlaid by an inline value not represented by a resource.
+            ConfigDescription best_frro_config;
+            Res_value best_frro_value;
+            bool frro_found = false;
+            for( const auto& [config, value] : overlay_entry.GetInlineValue()) {
+              if ((!frro_found || config.isBetterThan(best_frro_config, desired_config))
+                  && config.match(*desired_config)) {
+                frro_found = true;
+                best_frro_config = config;
+                best_frro_value = value;
+              }
+            }
+            if (!frro_found) {
+              continue;
+            }
+            result->entry = best_frro_value;
+            result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
+            result->cookie = id_map.cookie;
+
+            if (UNLIKELY(logging_enabled)) {
+              last_resolution_.steps.push_back(Resolution::Step{
+                  Resolution::Step::Type::OVERLAID_INLINE, result->cookie, String8()});
+              if (auto path = assets->GetPath()) {
+                const std::string overlay_path = path->data();
+                if (IsFabricatedOverlay(overlay_path)) {
+                  // FRRO don't have package name so we use the creating package here.
+                  String8 frro_name = String8("FRRO");
+                  // Get the first part of it since the expected one should be like
+                  // {overlayPackageName}-{overlayName}-{4 alphanumeric chars}.frro
+                  // under /data/resource-cache/.
+                  const std::string name = overlay_path.substr(overlay_path.rfind('/') + 1);
+                  const size_t end = name.find('-');
+                  if (frro_name.size() != overlay_path.size() && end != std::string::npos) {
+                    frro_name.append(base::StringPrintf(" created by %s",
+                                                        name.substr(0 /* pos */,
+                                                                    end).c_str()).c_str());
+                  }
+                  last_resolution_.best_package_name = frro_name;
+                } else {
+                  last_resolution_.best_package_name = result->package_name->c_str();
+                }
+              }
+              overlaid = true;
+            }
+            continue;
+          }
+
+          auto overlay_result = FindEntry(overlay_entry.GetResourceId(), density_override,
+                                          false /* stop_at_first_match */,
+                                          false /* ignore_configuration */);
+          if (UNLIKELY(IsIOError(overlay_result))) {
+            return base::unexpected(overlay_result.error());
+          }
+          if (!overlay_result.has_value()) {
+            continue;
+          }
+
+          if (!overlay_result->config.isBetterThan(result->config, desired_config)
+              && overlay_result->config.compare(result->config) != 0) {
+            // The configuration of the entry for the overlay must be equal to or better than the
+            // target configuration to be chosen as the better value.
+            continue;
+          }
+
+          result->cookie = overlay_result->cookie;
+          result->entry = overlay_result->entry;
+          result->config = overlay_result->config;
           result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
-          result->cookie = id_map.cookie;
 
           if (UNLIKELY(logging_enabled)) {
             last_resolution_.steps.push_back(
-                Resolution::Step{Resolution::Step::Type::OVERLAID_INLINE, result->cookie, String8()});
-            if (auto path = assets->GetPath()) {
-              const std::string overlay_path = path->data();
-              if (IsFabricatedOverlay(overlay_path)) {
-                // FRRO don't have package name so we use the creating package here.
-                String8 frro_name = String8("FRRO");
-                // Get the first part of it since the expected one should be like
-                // {overlayPackageName}-{overlayName}-{4 alphanumeric chars}.frro
-                // under /data/resource-cache/.
-                const std::string name = overlay_path.substr(overlay_path.rfind('/') + 1);
-                const size_t end = name.find('-');
-                if (frro_name.size() != overlay_path.size() && end != std::string::npos) {
-                  frro_name.append(base::StringPrintf(" created by %s",
-                                                      name.substr(0 /* pos */,
-                                                                  end).c_str()).c_str());
-                }
-                last_resolution_.best_package_name = frro_name;
-              } else {
-                last_resolution_.best_package_name = result->package_name->c_str();
-              }
-            }
+                Resolution::Step{Resolution::Step::Type::OVERLAID, overlay_result->cookie,
+                                 overlay_result->config.toString()});
+            last_resolution_.best_package_name =
+                overlay_result->package_name->c_str();
             overlaid = true;
           }
-          continue;
-        }
-
-        auto overlay_result = FindEntry(overlay_entry.GetResourceId(), density_override,
-                                        false /* stop_at_first_match */,
-                                        false /* ignore_configuration */);
-        if (UNLIKELY(IsIOError(overlay_result))) {
-          return base::unexpected(overlay_result.error());
-        }
-        if (!overlay_result.has_value()) {
-          continue;
-        }
-
-        if (!overlay_result->config.isBetterThan(result->config, desired_config)
-            && overlay_result->config.compare(result->config) != 0) {
-          // The configuration of the entry for the overlay must be equal to or better than the target
-          // configuration to be chosen as the better value.
-          continue;
-        }
-
-        result->cookie = overlay_result->cookie;
-        result->entry = overlay_result->entry;
-        result->config = overlay_result->config;
-        result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
-
-        if (UNLIKELY(logging_enabled)) {
-          last_resolution_.steps.push_back(
-              Resolution::Step{Resolution::Step::Type::OVERLAID, overlay_result->cookie,
-                               overlay_result->config.toString()});
-          last_resolution_.best_package_name =
-              overlay_result->package_name->c_str();
-          overlaid = true;
         }
       }
     }
+
+    bool has_locale = false;
+    if (result->config.locale == 0) {
+      if (default_locale_ != 0) {
+        ResTable_config conf;
+        conf.locale = default_locale_;
+        // Since we know conf has a locale and only a locale, match will tell us if that locale
+        // matches
+        has_locale = conf.match(config);
+      }
+    } else {
+      has_locale = true;
+    }
+
+    // if we don't have a result yet
+    if (!final_result ||
+        // or this config is better before the locale than the existing result
+        result->config.isBetterThanBeforeLocale(final_result->config, desired_config) ||
+        // or the existing config isn't better before locale and this one specifies a locale
+        // whereas the existing one doesn't
+        (!final_result->config.isBetterThanBeforeLocale(result->config, desired_config)
+            && has_locale && !final_has_locale)) {
+      final_result = result.value();
+      final_overlaid = overlaid;
+      final_has_locale = has_locale;
+    }
   }
 
   if (UNLIKELY(logging_enabled)) {
-    last_resolution_.cookie = result->cookie;
-    last_resolution_.type_string_ref = result->type_string_ref;
-    last_resolution_.entry_string_ref = result->entry_string_ref;
-    last_resolution_.best_config_name = result->config.toString();
-    if (!overlaid) {
-      last_resolution_.best_package_name = result->package_name->c_str();
+    last_resolution_.cookie = final_result->cookie;
+    last_resolution_.type_string_ref = final_result->type_string_ref;
+    last_resolution_.entry_string_ref = final_result->entry_string_ref;
+    last_resolution_.best_config_name = final_result->config.toString();
+    if (!final_overlaid) {
+      last_resolution_.best_package_name = final_result->package_name->c_str();
     }
   }
 
-  return result;
+  return *final_result;
 }
 
 base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal(
@@ -778,8 +821,10 @@
   // If `desired_config` is not the same as the set configuration or the caller will accept a value
   // from any configuration, then we cannot use our filtered list of types since it only it contains
   // types matched to the set configuration.
-  const bool use_filtered = !ignore_configuration && &desired_config == &configuration_;
-
+  const bool use_filtered = !ignore_configuration && std::find_if(
+      configurations_.begin(), configurations_.end(),
+      [&desired_config](auto& value) { return &desired_config == &value; })
+      != configurations_.end();
   const size_t package_count = package_group.packages_.size();
   for (size_t pi = 0; pi < package_count; pi++) {
     const ConfiguredPackage& loaded_package_impl = package_group.packages_[pi];
@@ -934,10 +979,22 @@
   }
 
   std::stringstream log_stream;
-  log_stream << base::StringPrintf("Resolution for 0x%08x %s\n"
-                                   "\tFor config - %s", resid, resource_name_string.c_str(),
-                                   configuration_.toString().c_str());
-
+  if (configurations_.size() == 1) {
+    log_stream << base::StringPrintf("Resolution for 0x%08x %s\n"
+                                     "\tFor config - %s", resid, resource_name_string.c_str(),
+                                     configurations_[0].toString().c_str());
+  } else {
+    ResTable_config conf = configurations_[0];
+    conf.clearLocale();
+    log_stream << base::StringPrintf("Resolution for 0x%08x %s\n\tFor config - %s and locales",
+                                     resid, resource_name_string.c_str(), conf.toString().c_str());
+    char str[40];
+    str[0] = '\0';
+    for(auto iter = configurations_.begin(); iter < configurations_.end(); iter++) {
+      iter->getBcp47Locale(str);
+      log_stream << base::StringPrintf(" %s%s", str, iter < configurations_.end() ? "," : "");
+    }
+  }
   for (const Resolution::Step& step : last_resolution_.steps) {
     constexpr static std::array kStepStrings = {
         "Found initial",
@@ -1423,11 +1480,14 @@
       package.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
         FilteredConfigGroup* group = nullptr;
         for (const auto& type_entry : type_spec.type_entries) {
-          if (type_entry.config.match(configuration_)) {
-            if (!group) {
-              group = &package.filtered_configs_.editItemAt(type_id - 1);
+          for (auto & config : configurations_) {
+            if (type_entry.config.match(config)) {
+              if (!group) {
+                group = &package.filtered_configs_.editItemAt(type_id - 1);
+              }
+              group->type_entries.push_back(&type_entry);
+              break;
             }
-            group->type_entries.push_back(&type_entry);
           }
         }
       });
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 5a63612..06d19e0 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -2568,6 +2568,22 @@
     return false;
 }
 
+bool ResTable_config::isBetterThanBeforeLocale(const ResTable_config& o,
+        const ResTable_config* requested) const {
+    if (requested) {
+        if (imsi || o.imsi) {
+            if ((mcc != o.mcc) && requested->mcc) {
+                return (mcc);
+            }
+
+            if ((mnc != o.mnc) && requested->mnc) {
+                return (mnc);
+            }
+        }
+    }
+    return false;
+}
+
 bool ResTable_config::isBetterThan(const ResTable_config& o,
         const ResTable_config* requested) const {
     if (requested) {
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index f611d0d..d9ff35b 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -100,7 +100,7 @@
   using ApkAssetsWPtr = wp<const ApkAssets>;
   using ApkAssetsList = std::span<const ApkAssetsPtr>;
 
-  AssetManager2() = default;
+  AssetManager2();
   explicit AssetManager2(AssetManager2&& other) = default;
   AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration);
 
@@ -156,10 +156,14 @@
 
   // Sets/resets the configuration for this AssetManager. This will cause all
   // caches that are related to the configuration change to be invalidated.
-  void SetConfiguration(const ResTable_config& configuration);
+  void SetConfigurations(std::vector<ResTable_config> configurations);
 
-  inline const ResTable_config& GetConfiguration() const {
-    return configuration_;
+  inline const std::vector<ResTable_config>& GetConfigurations() const {
+    return configurations_;
+  }
+
+  inline void SetDefaultLocale(uint32_t default_locale) {
+    default_locale_ = default_locale;
   }
 
   // Returns all configurations for which there are resources defined, or an I/O error if reading
@@ -465,9 +469,11 @@
   // without taking too much memory.
   std::array<uint8_t, std::numeric_limits<uint8_t>::max() + 1> package_ids_;
 
-  // The current configuration set for this AssetManager. When this changes, cached resources
+  uint32_t default_locale_;
+
+  // The current configurations set for this AssetManager. When this changes, cached resources
   // may need to be purged.
-  ResTable_config configuration_ = {};
+  std::vector<ResTable_config> configurations_;
 
   // Cached set of bags. These are cached because they can inherit keys from parent bags,
   // which involves some calculation.
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 4eb1d7a..52666ab 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1375,6 +1375,8 @@
     // match the requested configuration at all.
     bool isLocaleBetterThan(const ResTable_config& o, const ResTable_config* requested) const;
 
+    bool isBetterThanBeforeLocale(const ResTable_config& o, const ResTable_config* requested) const;
+
     String8 toString() const;
 };
 
diff --git a/libs/androidfw/tests/AssetManager2_bench.cpp b/libs/androidfw/tests/AssetManager2_bench.cpp
index 6fae72a..2caa98c 100644
--- a/libs/androidfw/tests/AssetManager2_bench.cpp
+++ b/libs/androidfw/tests/AssetManager2_bench.cpp
@@ -228,10 +228,12 @@
 
   ResTable_config config;
   memset(&config, 0, sizeof(config));
+  std::vector<ResTable_config> configs;
+  configs.push_back(config);
 
   while (state.KeepRunning()) {
-    config.sdkVersion = ~config.sdkVersion;
-    assets.SetConfiguration(config);
+    configs[0].sdkVersion = ~configs[0].sdkVersion;
+    assets.SetConfigurations(configs);
   }
 }
 BENCHMARK(BM_AssetManagerSetConfigurationFramework);
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index df3fa02..c62f095 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -113,7 +113,7 @@
   desired_config.language[1] = 'e';
 
   AssetManager2 assetmanager;
-  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetConfigurations({desired_config});
   assetmanager.SetApkAssets({basic_assets_});
 
   auto value = assetmanager.GetResource(basic::R::string::test1);
@@ -137,7 +137,7 @@
   desired_config.language[1] = 'e';
 
   AssetManager2 assetmanager;
-  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetConfigurations({desired_config});
   assetmanager.SetApkAssets({basic_assets_, basic_de_fr_assets_});
 
   auto value = assetmanager.GetResource(basic::R::string::test1);
@@ -466,10 +466,10 @@
 TEST_F(AssetManager2Test, DensityOverride) {
   AssetManager2 assetmanager;
   assetmanager.SetApkAssets({basic_assets_, basic_xhdpi_assets_, basic_xxhdpi_assets_});
-  assetmanager.SetConfiguration({
+  assetmanager.SetConfigurations({{
     .density = ResTable_config::DENSITY_XHIGH,
     .sdkVersion = 21,
-  });
+  }});
 
   auto value = assetmanager.GetResource(basic::R::string::density, false /*may_be_bag*/);
   ASSERT_TRUE(value.has_value());
@@ -721,7 +721,7 @@
   ResTable_config desired_config;
 
   AssetManager2 assetmanager;
-  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetConfigurations({desired_config});
   assetmanager.SetApkAssets({basic_assets_});
   assetmanager.SetResourceResolutionLoggingEnabled(false);
 
@@ -736,7 +736,7 @@
   ResTable_config desired_config;
 
   AssetManager2 assetmanager;
-  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetConfigurations({desired_config});
   assetmanager.SetApkAssets({basic_assets_});
 
   auto result = assetmanager.GetLastResourceResolution();
@@ -751,7 +751,7 @@
 
   AssetManager2 assetmanager;
   assetmanager.SetResourceResolutionLoggingEnabled(true);
-  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetConfigurations({desired_config});
   assetmanager.SetApkAssets({basic_assets_});
 
   auto value = assetmanager.GetResource(basic::R::string::test1);
@@ -774,7 +774,7 @@
 
   AssetManager2 assetmanager;
   assetmanager.SetResourceResolutionLoggingEnabled(true);
-  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetConfigurations({desired_config});
   assetmanager.SetApkAssets({basic_assets_, basic_de_fr_assets_});
 
   auto value = assetmanager.GetResource(basic::R::string::test1);
@@ -796,7 +796,7 @@
 
   AssetManager2 assetmanager;
   assetmanager.SetResourceResolutionLoggingEnabled(true);
-  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetConfigurations({desired_config});
   assetmanager.SetApkAssets({basic_assets_});
 
   auto value = assetmanager.GetResource(basic::R::string::test1);
@@ -817,7 +817,7 @@
 
   AssetManager2 assetmanager;
   assetmanager.SetResourceResolutionLoggingEnabled(true);
-  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetConfigurations({desired_config});
   assetmanager.SetApkAssets({overlayable_assets_});
 
   const auto map = assetmanager.GetOverlayableMapForPackage(0x7f);
diff --git a/libs/androidfw/tests/BenchmarkHelpers.cpp b/libs/androidfw/tests/BenchmarkHelpers.cpp
index b97dd96..8b883f4 100644
--- a/libs/androidfw/tests/BenchmarkHelpers.cpp
+++ b/libs/androidfw/tests/BenchmarkHelpers.cpp
@@ -66,7 +66,7 @@
   AssetManager2 assetmanager;
   assetmanager.SetApkAssets(apk_assets);
   if (config != nullptr) {
-    assetmanager.SetConfiguration(*config);
+    assetmanager.SetConfigurations({*config});
   }
 
   while (state.KeepRunning()) {
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index e08a6a7..181d141 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -260,7 +260,7 @@
   ResTable_config night{};
   night.uiMode = ResTable_config::UI_MODE_NIGHT_YES;
   night.version = 8u;
-  am_night.SetConfiguration(night);
+  am_night.SetConfigurations({night});
 
   auto theme = am.NewTheme();
   {
diff --git a/native/android/configuration.cpp b/native/android/configuration.cpp
index b50514d..283445f 100644
--- a/native/android/configuration.cpp
+++ b/native/android/configuration.cpp
@@ -36,7 +36,7 @@
 
 void AConfiguration_fromAssetManager(AConfiguration* out, AAssetManager* am) {
     ScopedLock<AssetManager2> locked_mgr(*AssetManagerForNdkAssetManager(am));
-    ResTable_config config = locked_mgr->GetConfiguration();
+    ResTable_config config = locked_mgr->GetConfigurations()[0];
 
     // AConfiguration is not a virtual subclass, so we can memcpy.
     memcpy(out, &config, sizeof(config));
diff --git a/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java b/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java
index a2177e8..0bb969f 100644
--- a/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java
+++ b/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java
@@ -17,13 +17,13 @@
 
 import android.content.pm.parsing.ApkLiteParseUtils;
 import android.content.pm.parsing.PackageLite;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
 import android.content.res.ApkAssets;
 import android.content.res.AssetManager;
 import android.os.Build;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
 
 import libcore.io.IoUtils;
 
@@ -82,8 +82,8 @@
         }
 
         AssetManager assets = new AssetManager();
-        assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                Build.VERSION.RESOURCES_SDK_INT);
+        assets.setConfiguration(0, 0, null, new String[0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, Build.VERSION.RESOURCES_SDK_INT);
         assets.setApkAssets(apkAssets, false /*invalidateCaches*/);
 
         mCachedAssetManager = assets;
diff --git a/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java b/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java
index 1a8c1996..56d92fb 100644
--- a/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java
+++ b/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java
@@ -80,8 +80,8 @@
 
     private static AssetManager createAssetManagerWithAssets(ApkAssets[] apkAssets) {
         final AssetManager assets = new AssetManager();
-        assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                Build.VERSION.RESOURCES_SDK_INT);
+        assets.setConfiguration(0, 0, null, new String[0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, Build.VERSION.RESOURCES_SDK_INT);
         assets.setApkAssets(apkAssets, false /*invalidateCaches*/);
         return assets;
     }