summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/ActivityThread.java64
-rw-r--r--core/java/android/app/ResourcesManager.java74
-rw-r--r--core/java/android/content/res/Configuration.java2
-rw-r--r--core/java/android/content/res/ResourcesImpl.java31
-rw-r--r--core/java/android/os/LocaleList.java14
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