diff options
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/app/ActivityThread.java | 64 | ||||
| -rw-r--r-- | core/java/android/app/ResourcesManager.java | 74 | ||||
| -rw-r--r-- | core/java/android/content/res/Configuration.java | 2 | ||||
| -rw-r--r-- | core/java/android/content/res/ResourcesImpl.java | 31 | ||||
| -rw-r--r-- | core/java/android/os/LocaleList.java | 14 |
5 files changed, 91 insertions, 94 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index dff07693c82f..30753c1632ff 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -62,6 +62,7 @@ import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; import android.os.IBinder; +import android.os.LocaleList; import android.os.Looper; import android.os.Message; import android.os.MessageQueue; @@ -130,6 +131,7 @@ import java.text.DateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.TimeZone; @@ -4684,6 +4686,8 @@ public final class ActivityThread { + config); mResourcesManager.applyConfigurationToResourcesLocked(config, compat); + updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(), + mResourcesManager.getConfiguration().getLocales()); if (mConfiguration == null) { mConfiguration = new Configuration(); @@ -4989,6 +4993,24 @@ public final class ActivityThread { return insInfo.nativeLibraryDir; } + /** + * The LocaleList set for the app's resources may have been shuffled so that the preferred + * Locale is at position 0. We must find the index of this preferred Locale in the + * original LocaleList. + */ + private void updateLocaleListFromAppContext(Context context, LocaleList newLocaleList) { + final Locale bestLocale = context.getResources().getConfiguration().getLocales().get(0); + final int newLocaleListSize = newLocaleList.size(); + for (int i = 0; i < newLocaleListSize; i++) { + if (bestLocale.equals(newLocaleList.get(i))) { + LocaleList.setDefault(newLocaleList, i); + return; + } + } + throw new AssertionError("chosen locale " + bestLocale + " must be present in LocaleList: " + + newLocaleList.toLanguageTags()); + } + private void handleBindApplication(AppBindData data) { // Register the UI Thread as a sensitive thread to the runtime. VMRuntime.registerSensitiveThread(); @@ -5047,6 +5069,24 @@ public final class ActivityThread { */ TimeZone.setDefault(null); + /* + * Set the LocaleList. This may change once we create the App Context. + */ + LocaleList.setDefault(data.config.getLocales()); + + synchronized (mResourcesManager) { + /* + * Update the system configuration since its preloaded and might not + * reflect configuration changes. The configuration object passed + * in AppBindData can be safely assumed to be up to date + */ + mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo); + mCurDefaultDisplayDpi = data.config.densityDpi; + + // This calls mResourcesManager so keep it within the synchronized block. + applyCompatConfiguration(mCurDefaultDisplayDpi); + } + data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo); /** @@ -5174,25 +5214,8 @@ public final class ActivityThread { } final ContextImpl appContext = ContextImpl.createAppContext(this, data.info); - synchronized (mResourcesManager) { - /* - * Initialize the default locales in this process for the reasons we set the time zone. - * - * We do this through ResourcesManager, since we need to do locale negotiation. - */ - mResourcesManager.setDefaultLocalesLocked(data.config.getLocales()); - - /* - * Update the system configuration since its preloaded and might not - * reflect configuration changes. The configuration object passed - * in AppBindData can be safely assumed to be up to date - */ - mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo); - mCurDefaultDisplayDpi = data.config.densityDpi; - - // This calls mResourcesManager so keep it within the synchronized block. - applyCompatConfiguration(mCurDefaultDisplayDpi); - } + updateLocaleListFromAppContext(appContext, + mResourcesManager.getConfiguration().getLocales()); if (!Process.isIsolated() && !"android".equals(appContext.getPackageName())) { // This cache location probably points at credential-encrypted @@ -5895,6 +5918,9 @@ public final class ActivityThread { // immediately, because upon returning the view // hierarchy will be informed about it. if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) { + updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(), + mResourcesManager.getConfiguration().getLocales()); + // This actually changed the resources! Tell // everyone about it. if (mPendingConfiguration == null || diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index b4e9db86d18c..25a8b66a42aa 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -67,10 +67,6 @@ public class ResourcesManager { } }; - private String[] mSystemLocales = null; - private final HashSet<String> mNonSystemLocales = new HashSet<>(); - private boolean mHasNonSystemLocales = false; - /** * The global compatibility settings. */ @@ -479,12 +475,7 @@ public class ResourcesManager { */ private Resources getOrCreateResources(@Nullable IBinder activityToken, @NonNull ResourcesKey key, @NonNull ClassLoader classLoader) { - final boolean findSystemLocales; - final boolean hasNonSystemLocales; synchronized (this) { - findSystemLocales = (mSystemLocales == null || mSystemLocales.length == 0); - hasNonSystemLocales = mHasNonSystemLocales; - if (DEBUG) { Throwable here = new Throwable(); here.fillInStackTrace(); @@ -538,24 +529,7 @@ public class ResourcesManager { // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now. ResourcesImpl resourcesImpl = createResourcesImpl(key); - final String[] systemLocales = findSystemLocales - ? AssetManager.getSystem().getLocales() : null; - final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales(); - - // Avoid checking for non-pseudo-locales if we already know there were some from a previous - // Resources. The default value (for when hasNonSystemLocales is true) doesn't matter, - // since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be - // able to affect mHasNonSystemLocales. - final boolean isPseudoLocalesOnly = hasNonSystemLocales || - LocaleList.isPseudoLocalesOnly(nonSystemLocales); - synchronized (this) { - if (mSystemLocales == null || mSystemLocales.length == 0) { - mSystemLocales = systemLocales; - } - mNonSystemLocales.addAll(Arrays.asList(nonSystemLocales)); - mHasNonSystemLocales = mHasNonSystemLocales || !isPseudoLocalesOnly; - ResourcesImpl existingResourcesImpl = findResourcesImplForKeyLocked(key); if (existingResourcesImpl != null) { if (DEBUG) { @@ -745,23 +719,6 @@ public class ResourcesManager { } } - /* package */ void setDefaultLocalesLocked(@NonNull LocaleList locales) { - if (mSystemLocales == null) { - throw new RuntimeException("ResourcesManager is not ready to negotiate locales."); - } - final int bestLocale; - if (mHasNonSystemLocales) { - bestLocale = locales.getFirstMatchIndexWithEnglishSupported(mNonSystemLocales); - } else { - // We fallback to system locales if there was no locale specifically supported by the - // assets. This is to properly support apps that only rely on the shared system assets - // and don't need assets of their own. - bestLocale = locales.getFirstMatchIndexWithEnglishSupported(mSystemLocales); - } - // set it for Java, this also affects newly created Resources - LocaleList.setDefault(locales, bestLocale); - } - public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config, @Nullable CompatibilityInfo compat) { try { @@ -786,30 +743,7 @@ public class ResourcesManager { | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; } - Configuration localeAdjustedConfig = config; - final LocaleList configLocales = config.getLocales(); - if (!configLocales.isEmpty()) { - setDefaultLocalesLocked(configLocales); - final LocaleList adjustedLocales = LocaleList.getAdjustedDefault(); - if (adjustedLocales - != configLocales) { // has the same result as .equals() in this case - // The first locale in the list was not chosen. So we create a modified - // configuration with the adjusted locales (which moves the chosen locale to the - // front). - localeAdjustedConfig = new Configuration(); - localeAdjustedConfig.setTo(config); - localeAdjustedConfig.setLocales(adjustedLocales); - // Also adjust the locale list in mResConfiguration, so that the Resources - // created later would have the same locale list. - if (!mResConfiguration.getLocales().equals(adjustedLocales)) { - mResConfiguration.setLocales(adjustedLocales); - changes |= ActivityInfo.CONFIG_LOCALE; - } - } - } - - Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics, - compat); + Resources.updateSystemConfiguration(config, defaultDisplayMetrics, compat); ApplicationPackageManager.configurationChanged(); //Slog.i(TAG, "Configuration changed in " + currentPackageName()); @@ -821,7 +755,7 @@ public class ResourcesManager { ResourcesImpl r = mResourceImpls.valueAt(i).get(); if (r != null) { if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources " - + r + " config to: " + localeAdjustedConfig); + + r + " config to: " + config); int displayId = key.mDisplayId; boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY); DisplayMetrics dm = defaultDisplayMetrics; @@ -830,7 +764,7 @@ public class ResourcesManager { if (tmpConfig == null) { tmpConfig = new Configuration(); } - tmpConfig.setTo(localeAdjustedConfig); + tmpConfig.setTo(config); if (!isDefaultDisplay) { dm = getDisplayMetrics(displayId); applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig); @@ -840,7 +774,7 @@ public class ResourcesManager { } r.updateConfiguration(tmpConfig, dm, compat); } else { - r.updateConfiguration(localeAdjustedConfig, dm, compat); + r.updateConfiguration(config, dm, compat); } //Slog.i(TAG, "Updated app resources " + v.getKey() // + " " + r + ": " + r.getConfiguration()); diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index c1aac8584acb..f6445e6cd090 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -1446,7 +1446,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration * * @return The locale list. */ - public LocaleList getLocales() { + public @NonNull LocaleList getLocales() { fixUpLocaleList(); return mLocaleList; } diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index dada61280c1e..32a27951677a 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -330,18 +330,43 @@ public class ResourcesImpl { // doing the conversion here. This impl should be okay because // we make sure to return a compatible display in the places // where there are public APIs to retrieve the display... but - // it would be cleaner and more maintainble to just be + // it would be cleaner and more maintainable to just be // consistently dealing with a compatible display everywhere in // the framework. mCompatibilityInfo.applyToDisplayMetrics(mMetrics); final @Config int configChanges = calcConfigChanges(config); + // If even after the update there are no Locales set, grab the default locales. LocaleList locales = mConfiguration.getLocales(); if (locales.isEmpty()) { - locales = LocaleList.getAdjustedDefault(); + locales = LocaleList.getDefault(); mConfiguration.setLocales(locales); } + + if ((configChanges & ActivityInfo.CONFIG_LOCALE) != 0) { + if (locales.size() > 1) { + // The LocaleList has changed. We must query the AssetManager's available + // Locales and figure out the best matching Locale in the new LocaleList. + String[] availableLocales = mAssets.getNonSystemLocales(); + if (LocaleList.isPseudoLocalesOnly(availableLocales)) { + // No app defined locales, so grab the system locales. + availableLocales = mAssets.getLocales(); + if (LocaleList.isPseudoLocalesOnly(availableLocales)) { + 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 (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) { mMetrics.densityDpi = mConfiguration.densityDpi; mMetrics.density = @@ -370,7 +395,7 @@ public class ResourcesImpl { } mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc, - adjustLanguageTag(locales.get(0).toLanguageTag()), + adjustLanguageTag(mConfiguration.getLocales().get(0).toLanguageTag()), 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 8136796574e0..60b618a2f689 100644 --- a/core/java/android/os/LocaleList.java +++ b/core/java/android/os/LocaleList.java @@ -409,6 +409,14 @@ public final class LocaleList implements Parcelable { } /** + * {@hide} + */ + public int getFirstMatchIndex(String[] supportedLocales) { + return computeFirstMatchIndex(Arrays.asList(supportedLocales), + false /* assume English is not supported */); + } + + /** * Same as getFirstMatch(), but with English assumed to be supported, even if it's not. * {@hide} */ @@ -437,7 +445,11 @@ public final class LocaleList implements Parcelable { * Assumes that there is no repetition in the input. * {@hide} */ - public static boolean isPseudoLocalesOnly(String[] supportedLocales) { + public static boolean isPseudoLocalesOnly(@Nullable String[] supportedLocales) { + if (supportedLocales == null) { + return true; + } + if (supportedLocales.length > NUM_PSEUDO_LOCALES + 1) { // This is for optimization. Since there's no repetition in the input, if we have more // than the number of pseudo-locales plus one for the empty string, it's guaranteed |
