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
This commit is contained in:
@@ -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 ||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -408,6 +408,14 @@ public final class LocaleList implements Parcelable {
|
||||
false /* assume English is not supported */);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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
|
||||
|
||||
8
core/tests/coretests/apks/locales/Android.mk
Normal file
8
core/tests/coretests/apks/locales/Android.mk
Normal file
@@ -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)
|
||||
21
core/tests/coretests/apks/locales/AndroidManifest.xml
Normal file
21
core/tests/coretests/apks/locales/AndroidManifest.xml
Normal file
@@ -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>
|
||||
18
core/tests/coretests/apks/locales/res/values-pl/values.xml
Normal file
18
core/tests/coretests/apks/locales/res/values-pl/values.xml
Normal file
@@ -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>
|
||||
18
core/tests/coretests/apks/locales/res/values/values.xml
Normal file
18
core/tests/coretests/apks/locales/res/values/values.xml
Normal file
@@ -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>
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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++;
|
||||
|
||||
Reference in New Issue
Block a user