summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Adam Lesinski <adamlesinski@google.com> 2016-05-24 21:41:20 +0000
committer android-build-merger <android-build-merger@google.com> 2016-05-24 21:41:20 +0000
commit9ed84d86120dd6487eacba503f45f6d147f05fbf (patch)
tree63efb7557e624417ce3c233f2ef35b3e19f60213
parent4d1d0bcc4a9342f2b41827d852145a2b66a795b6 (diff)
parent5e106dea4545547f3f7c50dad30f792809659b96 (diff)
Merge "Improve performance of LocaleList with Resources" into nyc-dev am: bb26248bbb
am: 5e106dea45 * commit '5e106dea4545547f3f7c50dad30f792809659b96': Improve performance of LocaleList with Resources Change-Id: I733cdad0b30069ac7830fa91ef0188dd0f0cfac9
-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
-rw-r--r--core/tests/coretests/apks/locales/Android.mk8
-rw-r--r--core/tests/coretests/apks/locales/AndroidManifest.xml21
-rw-r--r--core/tests/coretests/apks/locales/res/values-pl/values.xml18
-rw-r--r--core/tests/coretests/apks/locales/res/values/values.xml18
-rw-r--r--core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java97
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java18
11 files changed, 262 insertions, 103 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7fc64e73eaf2..635bd75c44bd 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();
@@ -4987,6 +4991,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();
@@ -5045,6 +5067,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);
/**
@@ -5172,25 +5212,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
@@ -5893,6 +5916,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
diff --git a/core/tests/coretests/apks/locales/Android.mk b/core/tests/coretests/apks/locales/Android.mk
new file mode 100644
index 000000000000..9cb13dd4cd0e
--- /dev/null
+++ b/core/tests/coretests/apks/locales/Android.mk
@@ -0,0 +1,8 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := locales
+
+include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/locales/AndroidManifest.xml b/core/tests/coretests/apks/locales/AndroidManifest.xml
new file mode 100644
index 000000000000..8a1f575510e7
--- /dev/null
+++ b/core/tests/coretests/apks/locales/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.locales">
+
+ <application android:hasCode="false">
+ </application>
+</manifest>
diff --git a/core/tests/coretests/apks/locales/res/values-pl/values.xml b/core/tests/coretests/apks/locales/res/values-pl/values.xml
new file mode 100644
index 000000000000..22237fa81001
--- /dev/null
+++ b/core/tests/coretests/apks/locales/res/values-pl/values.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<resources>
+ <string name="text">Text (pl)</string>
+</resources>
diff --git a/core/tests/coretests/apks/locales/res/values/values.xml b/core/tests/coretests/apks/locales/res/values/values.xml
new file mode 100644
index 000000000000..cb990d20215e
--- /dev/null
+++ b/core/tests/coretests/apks/locales/res/values/values.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<resources>
+ <string name="text">Text</string>
+</resources>
diff --git a/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java b/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java
new file mode 100644
index 000000000000..e85666eb1639
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016 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 android.os.FileUtils;
+import android.os.LocaleList;
+import android.support.test.filters.SmallTest;
+import android.test.AndroidTestCase;
+import android.util.DisplayMetrics;
+import android.view.Display;
+
+import com.android.frameworks.coretests.R;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Locale;
+
+public class ResourcesLocaleTest extends AndroidTestCase {
+
+ private String extractApkAndGetPath(int id) throws Exception {
+ final Resources resources = getContext().getResources();
+ try (InputStream is = resources.openRawResource(id)) {
+ File path = new File(getContext().getFilesDir(), resources.getResourceEntryName(id));
+ FileUtils.copyToFileOrThrow(is, path);
+ return path.getAbsolutePath();
+ }
+ }
+
+ private Resources createResourcesWithApk(int rawApkId) throws Exception {
+ final AssetManager assets = new AssetManager();
+ assertTrue(assets.addAssetPath(extractApkAndGetPath(rawApkId)) != 0);
+
+ final DisplayMetrics dm = new DisplayMetrics();
+ dm.setToDefaults();
+ return new Resources(assets, dm, new Configuration());
+ }
+
+ private static void ensureNoLanguage(Resources resources, String language) {
+ final String[] supportedLocales = resources.getAssets().getNonSystemLocales();
+ for (String languageTag : supportedLocales) {
+ if ("en-XA".equals(languageTag)) {
+ continue;
+ }
+ assertFalse(
+ "supported locales: " + Arrays.toString(supportedLocales),
+ language.equals(Locale.forLanguageTag(languageTag).getLanguage()));
+ }
+ }
+
+ @SmallTest
+ public void testEnglishIsAlwaysConsideredSupported() throws Exception {
+ final Resources resources = createResourcesWithApk(R.raw.locales);
+ ensureNoLanguage(resources, "en");
+
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("en-US,pl-PL");
+ final Configuration config = new Configuration();
+ config.setLocales(preferredLocales);
+
+ resources.updateConfiguration(config, null);
+
+ // The APK we loaded has default and Polish languages. If English is first in the list,
+ // always take it the default (assumed to be English).
+ assertEquals(Locale.forLanguageTag("en-US"),
+ resources.getConfiguration().getLocales().get(0));
+ }
+
+ @SmallTest
+ public void testSelectFirstSupportedLanguage() throws Exception {
+ final Resources resources = createResourcesWithApk(R.raw.locales);
+ ensureNoLanguage(resources, "fr");
+
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("fr-FR,pl-PL");
+ final Configuration config = new Configuration();
+ config.setLocales(preferredLocales);
+
+ resources.updateConfiguration(config, null);
+
+ // The APK we loaded has default and Polish languages. We expect the Polish language to
+ // therefore be chosen.
+ assertEquals(Locale.forLanguageTag("pl-PL"),
+ resources.getConfiguration().getLocales().get(0));
+ }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 808b254aa738..f4bb524ff156 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18325,21 +18325,21 @@ public final class ActivityManagerService extends ActivityManagerNative
EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
- final Locale locale;
- if (values.getLocales().size() == 1) {
- // This is an optimization to avoid the JNI call when the result of
- // getFirstMatch() does not depend on the supported locales.
- locale = values.getLocales().get(0);
- } else {
+ final LocaleList locales = values.getLocales();
+ int bestLocaleIndex = 0;
+ if (locales.size() > 1) {
if (mSupportedSystemLocales == null) {
mSupportedSystemLocales =
Resources.getSystem().getAssets().getLocales();
}
- locale = values.getLocales().getFirstMatch(mSupportedSystemLocales);
+ bestLocaleIndex = Math.max(0,
+ locales.getFirstMatchIndex(mSupportedSystemLocales));
}
- SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
+ SystemProperties.set("persist.sys.locale",
+ locales.get(bestLocaleIndex).toLanguageTag());
+ LocaleList.setDefault(locales, bestLocaleIndex);
mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
- locale));
+ locales.get(bestLocaleIndex)));
}
mConfigurationSeq++;