summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Roozbeh Pournader <roozbeh@google.com> 2016-01-23 22:34:57 -0800
committer Roozbeh Pournader <roozbeh@google.com> 2016-01-25 19:23:38 -0800
commit834641b3908b21e7054c290e116d76e3d5e6888c (patch)
tree8b407b8a610bb8b817f4a0ded3a5063b36886156
parentac7c606c90bcf3bfea2b04f518680baf5549b9f5 (diff)
Move locale negotiation to ResourcesManager
Previously, locale resolution happened at Resources level, which could result in different Resources in the same app using different locales. This change moves the locale negotiation to ResourcesManager, which remembers the locales supported by each Resources as they are created, and negotiates the locale based on their union. It also makes sure that the old model of apps getting the default locale by accessing it through the Configuration's locale attribute continues to work, since the negotiated locale will be moved to the top of the list before Resources are created and when they are updated with a Configuration change. Bug: 25800576 Bug: 26404653 Change-Id: I0dd81df288327fd8d1229188c9544ee2209c161a
-rw-r--r--api/current.txt1
-rw-r--r--api/system-current.txt1
-rw-r--r--api/test-current.txt1
-rw-r--r--core/java/android/app/ActivityThread.java4
-rw-r--r--core/java/android/app/ResourcesManager.java75
-rw-r--r--core/java/android/content/res/Resources.java44
-rw-r--r--core/java/android/util/LocaleList.java121
-rw-r--r--core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java53
8 files changed, 164 insertions, 136 deletions
diff --git a/api/current.txt b/api/current.txt
index e0b92f4039b5..ae44b40494c3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10085,7 +10085,6 @@ package android.content.res {
method public java.lang.String getQuantityString(int, int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getQuantityString(int, int) throws android.content.res.Resources.NotFoundException;
method public java.lang.CharSequence getQuantityText(int, int) throws android.content.res.Resources.NotFoundException;
- method public java.util.Locale getResolvedLocale();
method public java.lang.String getResourceEntryName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourceName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourcePackageName(int) throws android.content.res.Resources.NotFoundException;
diff --git a/api/system-current.txt b/api/system-current.txt
index 6b84f5672608..87e2e21d80cc 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -10480,7 +10480,6 @@ package android.content.res {
method public java.lang.String getQuantityString(int, int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getQuantityString(int, int) throws android.content.res.Resources.NotFoundException;
method public java.lang.CharSequence getQuantityText(int, int) throws android.content.res.Resources.NotFoundException;
- method public java.util.Locale getResolvedLocale();
method public java.lang.String getResourceEntryName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourceName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourcePackageName(int) throws android.content.res.Resources.NotFoundException;
diff --git a/api/test-current.txt b/api/test-current.txt
index f0038758ae70..20b0e6392df1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -10093,7 +10093,6 @@ package android.content.res {
method public java.lang.String getQuantityString(int, int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getQuantityString(int, int) throws android.content.res.Resources.NotFoundException;
method public java.lang.CharSequence getQuantityText(int, int) throws android.content.res.Resources.NotFoundException;
- method public java.util.Locale getResolvedLocale();
method public java.lang.String getResourceEntryName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourceName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourcePackageName(int) throws android.content.res.Resources.NotFoundException;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7b0195391b47..929bb7242cfc 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4888,8 +4888,10 @@ public final class ActivityThread {
/*
* 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.
*/
- LocaleList.setDefault(data.config.getLocales());
+ mResourcesManager.setDefaultLocalesLocked(data.config.getLocales());
/*
* Update the system configuration since its preloaded and might not
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 260216cfefb8..94e584eeaa98 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -35,6 +35,9 @@ import android.view.Display;
import android.view.DisplayAdjustments;
import java.lang.ref.WeakReference;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
/** @hide */
public class ResourcesManager {
@@ -42,11 +45,15 @@ public class ResourcesManager {
private static final boolean DEBUG = false;
private static ResourcesManager sResourcesManager;
- private final ArrayMap<ResourcesKey, WeakReference<Resources> > mActiveResources =
+ private final ArrayMap<ResourcesKey, WeakReference<Resources>> mActiveResources =
new ArrayMap<>();
private final ArrayMap<Pair<Integer, DisplayAdjustments>, WeakReference<Display>> mDisplays =
new ArrayMap<>();
+ private String[] mSystemLocales = {};
+ private final HashSet<String> mNonSystemLocales = new HashSet<String>();
+ private boolean mHasNonSystemLocales = false;
+
CompatibilityInfo mResCompatibilityInfo;
Configuration mResConfiguration;
@@ -165,6 +172,8 @@ public class ResourcesManager {
? new Configuration(overrideConfiguration) : null;
ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfigCopy, scale);
Resources r;
+ final boolean findSystemLocales;
+ final boolean hasNonSystemLocales;
synchronized (this) {
// Resources is app scale dependent.
if (DEBUG) Slog.w(TAG, "getTopLevelResources: " + resDir + " / " + scale);
@@ -178,6 +187,8 @@ public class ResourcesManager {
+ " key=" + key + " overrideConfig=" + overrideConfiguration);
return r;
}
+ findSystemLocales = (mSystemLocales.length == 0);
+ hasNonSystemLocales = mHasNonSystemLocales;
}
//if (r != null) {
@@ -243,6 +254,18 @@ public class ResourcesManager {
if (DEBUG) Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
+ r.getConfiguration() + " appScale=" + r.getCompatibilityInfo().applicationScale);
+ final String[] systemLocales = (
+ findSystemLocales ?
+ AssetManager.getSystem().getLocales() :
+ null);
+ final String[] nonSystemLocales = assets.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) {
WeakReference<Resources> wr = mActiveResources.get(key);
Resources existing = wr != null ? wr.get() : null;
@@ -255,11 +278,30 @@ public class ResourcesManager {
// XXX need to remove entries when weak references go away
mActiveResources.put(key, new WeakReference<>(r));
+ if (mSystemLocales.length == 0) {
+ mSystemLocales = systemLocales;
+ }
+ mNonSystemLocales.addAll(Arrays.asList(nonSystemLocales));
+ mHasNonSystemLocales = mHasNonSystemLocales || !isPseudoLocalesOnly;
if (DEBUG) Slog.v(TAG, "mActiveResources.size()=" + mActiveResources.size());
return r;
}
}
+ /* package */ void setDefaultLocalesLocked(LocaleList 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);
+ }
+
final boolean applyConfigurationToResourcesLocked(Configuration config,
CompatibilityInfo compat) {
if (mResConfiguration == null) {
@@ -283,13 +325,28 @@ public class ResourcesManager {
| ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
}
- // set it for java, this also affects newly created Resources
- final LocaleList localeList = config.getLocales();
- if (!localeList.isEmpty()) {
- LocaleList.setDefault(localeList);
+ 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(config, defaultDisplayMetrics, compat);
+ Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics, compat);
ApplicationPackageManager.configurationChanged();
//Slog.i(TAG, "Configuration changed in " + currentPackageName());
@@ -301,7 +358,7 @@ public class ResourcesManager {
Resources r = mActiveResources.valueAt(i).get();
if (r != null) {
if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
- + r + " config to: " + config);
+ + r + " config to: " + localeAdjustedConfig);
int displayId = key.mDisplayId;
boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
DisplayMetrics dm = defaultDisplayMetrics;
@@ -310,7 +367,7 @@ public class ResourcesManager {
if (tmpConfig == null) {
tmpConfig = new Configuration();
}
- tmpConfig.setTo(config);
+ tmpConfig.setTo(localeAdjustedConfig);
if (!isDefaultDisplay) {
dm = getDisplayMetricsLocked(displayId);
applyNonDefaultDisplayMetricsToConfigurationLocked(dm, tmpConfig);
@@ -320,7 +377,7 @@ public class ResourcesManager {
}
r.updateConfiguration(tmpConfig, dm, compat);
} else {
- r.updateConfiguration(config, dm, compat);
+ r.updateConfiguration(localeAdjustedConfig, dm, compat);
}
//Slog.i(TAG, "Updated app resources " + v.getKey()
// + " " + r + ": " + r.getConfiguration());
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index ed64eade0351..e4044296dac4 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -162,10 +162,6 @@ public class Resources {
private final Configuration mConfiguration = new Configuration();
- // Invariant: mResolvedLocale is the resolved locale of mLocalesForResolved
- private LocaleList mLocalesForResolved = null;
- private Locale mResolvedLocale = null;
-
private PluralRules mPluralRule;
private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
@@ -321,16 +317,6 @@ public class Resources {
}
/**
- * Return the Locale resulting from locale negotiation between the Resources and the
- * Configuration objects used to construct the Resources. The locale is used for retrieving
- * resources as well as for determining plural rules.
- */
- @NonNull
- public Locale getResolvedLocale() {
- return mResolvedLocale;
- }
-
- /**
* Return the string value associated with a particular resource ID. The
* returned object will be a String if this is a plain string; it will be
* some other type of CharSequence if it is styled.
@@ -394,7 +380,7 @@ public class Resources {
private PluralRules getPluralRule() {
synchronized (sSync) {
if (mPluralRule == null) {
- mPluralRule = PluralRules.forLocale(mResolvedLocale);
+ mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().getPrimary());
}
return mPluralRule;
}
@@ -457,7 +443,7 @@ public class Resources {
@NonNull
public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException {
final String raw = getString(id);
- return String.format(mResolvedLocale, raw, formatArgs);
+ return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs);
}
/**
@@ -488,7 +474,7 @@ public class Resources {
public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)
throws NotFoundException {
String raw = getQuantityText(id, quantity).toString();
- return String.format(mResolvedLocale, raw, formatArgs);
+ return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs);
}
/**
@@ -1955,7 +1941,7 @@ public class Resources {
LocaleList locales = mConfiguration.getLocales();
if (locales.isEmpty()) {
- locales = LocaleList.getDefault();
+ locales = LocaleList.getAdjustedDefault();
mConfiguration.setLocales(locales);
}
if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
@@ -1983,26 +1969,8 @@ public class Resources {
keyboardHidden = mConfiguration.keyboardHidden;
}
- if (locales != mLocalesForResolved) {
- if (locales.size() == 1) {
- // This is an optimization to avoid the JNI call(s) when the result of
- // getFirstMatchWithEnglishSupported() does not depend on the supported locales.
- mResolvedLocale = locales.getPrimary();
- } else {
- String[] supportedLocales = mAssets.getNonSystemLocales();
- if (LocaleList.isPseudoLocalesOnly(supportedLocales)) {
- // We fallback to all locales (including 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.
- supportedLocales = mAssets.getLocales();
- }
- mResolvedLocale = locales.getFirstMatchWithEnglishSupported(supportedLocales);
- }
- mLocalesForResolved = locales;
- }
mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
- adjustLanguageTag(mResolvedLocale.toLanguageTag()),
+ adjustLanguageTag(locales.getPrimary().toLanguageTag()),
mConfiguration.orientation,
mConfiguration.touchscreen,
mConfiguration.densityDpi, mConfiguration.keyboard,
@@ -2027,7 +1995,7 @@ public class Resources {
}
synchronized (sSync) {
if (mPluralRule != null) {
- mPluralRule = PluralRules.forLocale(mResolvedLocale);
+ mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().getPrimary());
}
}
}
diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java
index 8a2d015a6f7b..90a20bc2ab24 100644
--- a/core/java/android/util/LocaleList.java
+++ b/core/java/android/util/LocaleList.java
@@ -26,6 +26,8 @@ import android.os.Parcelable;
import com.android.internal.annotations.GuardedBy;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.HashSet;
import java.util.Locale;
@@ -317,55 +319,72 @@ public final class LocaleList implements Parcelable {
return supportedScr.equals(desiredScr) ? 1 : 0;
}
+ private int findFirstMatchIndex(Locale supportedLocale) {
+ for (int idx = 0; idx < mList.length; idx++) {
+ final int score = matchScore(supportedLocale, mList[idx]);
+ if (score > 0) {
+ return idx;
+ }
+ }
+ return Integer.MAX_VALUE;
+ }
+
private static final Locale EN_LATN = Locale.forLanguageTag("en-Latn");
- private Locale computeFirstMatch(String[] supportedLocales, boolean assumeEnglishIsSupported) {
+ private int computeFirstMatchIndex(Collection<String> supportedLocales,
+ boolean assumeEnglishIsSupported) {
if (mList.length == 1) { // just one locale, perhaps the most common scenario
- return mList[0];
+ return 0;
}
if (mList.length == 0) { // empty locale list
- return null;
+ return -1;
}
+
int bestIndex = Integer.MAX_VALUE;
- final int numSupportedLocales =
- supportedLocales.length + (assumeEnglishIsSupported ? 1 : 0);
- for (int i = 0; i < numSupportedLocales; i++) {
- final Locale supportedLocale;
- if (assumeEnglishIsSupported) {
- // Try English first, so we can return early if it's in the LocaleList
- supportedLocale = (i == 0) ? EN_LATN : Locale.forLanguageTag(supportedLocales[i-1]);
- } else {
- supportedLocale = Locale.forLanguageTag(supportedLocales[i]);
+ // Try English first, so we can return early if it's in the LocaleList
+ if (assumeEnglishIsSupported) {
+ final int idx = findFirstMatchIndex(EN_LATN);
+ if (idx == 0) { // We have a match on the first locale, which is good enough
+ return 0;
+ } else if (idx < bestIndex) {
+ bestIndex = idx;
}
+ }
+ for (String languageTag : supportedLocales) {
+ final Locale supportedLocale = Locale.forLanguageTag(languageTag);
// We expect the average length of locale lists used for locale resolution to be
// smaller than three, so it's OK to do this as an O(mn) algorithm.
- for (int idx = 0; idx < mList.length; idx++) {
- final int score = matchScore(supportedLocale, mList[idx]);
- if (score > 0) {
- if (idx == 0) { // We have a match on the first locale, which is good enough
- return mList[0];
- } else if (idx < bestIndex) {
- bestIndex = idx;
- }
- }
+ final int idx = findFirstMatchIndex(supportedLocale);
+ if (idx == 0) { // We have a match on the first locale, which is good enough
+ return 0;
+ } else if (idx < bestIndex) {
+ bestIndex = idx;
}
}
- if (bestIndex == Integer.MAX_VALUE) { // no match was found
- return mList[0];
+ if (bestIndex == Integer.MAX_VALUE) {
+ // no match was found, so we fall back to the first locale in the locale list
+ return 0;
} else {
- return mList[bestIndex];
+ return bestIndex;
}
}
+ private Locale computeFirstMatch(Collection<String> supportedLocales,
+ boolean assumeEnglishIsSupported) {
+ int bestIndex = computeFirstMatchIndex(supportedLocales, assumeEnglishIsSupported);
+ return bestIndex == -1 ? null : mList[bestIndex];
+ }
+
/**
* Returns the first match in the locale list given an unordered array of supported locales
- * in BCP47 format.
+ * in BCP 47 format.
*
* If the locale list is empty, null would be returned.
*/
@Nullable
public Locale getFirstMatch(String[] supportedLocales) {
- return computeFirstMatch(supportedLocales, false /* assume English is not supported */);
+ return computeFirstMatch(Arrays.asList(supportedLocales),
+ false /* assume English is not supported */);
}
/**
@@ -374,11 +393,26 @@ public final class LocaleList implements Parcelable {
*/
@Nullable
public Locale getFirstMatchWithEnglishSupported(String[] supportedLocales) {
- return computeFirstMatch(supportedLocales, true /* assume English is supported */);
+ return computeFirstMatch(Arrays.asList(supportedLocales),
+ true /* assume English is supported */);
+ }
+
+ /**
+ * {@hide}
+ */
+ public int getFirstMatchIndexWithEnglishSupported(Collection<String> supportedLocales) {
+ return computeFirstMatchIndex(supportedLocales, true /* assume English is supported */);
}
/**
- * Returns true if the array of locale tags only contains empty locales and pseudolocales.
+ * {@hide}
+ */
+ public int getFirstMatchIndexWithEnglishSupported(String[] supportedLocales) {
+ return getFirstMatchIndexWithEnglishSupported(Arrays.asList(supportedLocales));
+ }
+
+ /**
+ * Returns true if the collection of locale tags only contains empty locales and pseudolocales.
* Assumes that there is no repetition in the input.
* {@hide}
*/
@@ -386,7 +420,7 @@ public final class LocaleList implements Parcelable {
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
- // that we have some meaninful locale in the list, so the list is not "practically
+ // that we have some meaninful locale in the collection, so the list is not "practically
// empty".
return false;
}
@@ -405,6 +439,8 @@ public final class LocaleList implements Parcelable {
@GuardedBy("sLock")
private static LocaleList sDefaultLocaleList = null;
@GuardedBy("sLock")
+ private static LocaleList sDefaultAdjustedLocaleList = null;
+ @GuardedBy("sLock")
private static Locale sLastDefaultLocale = null;
/**
@@ -415,8 +451,8 @@ public final class LocaleList implements Parcelable {
* secondary preference is.
*
* Note that the default LocaleList would change if Locale.setDefault() is called. This method
- * takes that into account by always checking the output of Locale.getDefault() and adjusting
- * the default LocaleList if needed.
+ * takes that into account by always checking the output of Locale.getDefault() and
+ * recalculating the default LocaleList if needed.
*/
@NonNull @Size(min=1)
public static LocaleList getDefault() {
@@ -426,7 +462,7 @@ public final class LocaleList implements Parcelable {
sLastDefaultLocale = defaultLocale;
// It's either the first time someone has asked for the default locale list, or
// someone has called Locale.setDefault() since we last set or adjusted the default
- // locale list. So let's adjust the locale list.
+ // locale list. So let's recalculate the locale list.
if (sDefaultLocaleList != null
&& defaultLocale.equals(sDefaultLocaleList.getPrimary())) {
// The default Locale has changed, but it happens to be the first locale in the
@@ -434,6 +470,7 @@ public final class LocaleList implements Parcelable {
return sDefaultLocaleList;
}
sDefaultLocaleList = new LocaleList(defaultLocale, sLastExplicitlySetLocaleList);
+ sDefaultAdjustedLocaleList = sDefaultLocaleList;
}
// sDefaultLocaleList can't be null, since it can't be set to null by
// LocaleList.setDefault(), and if getDefault() is called before a call to
@@ -444,6 +481,20 @@ public final class LocaleList implements Parcelable {
}
/**
+ * Returns the default locale list, adjusted by moving the default locale to its first
+ * position.
+ *
+ * {@hide}
+ */
+ @NonNull @Size(min=1)
+ public static LocaleList getAdjustedDefault() {
+ getDefault(); // to recalculate the default locale list, if necessary
+ synchronized (sLock) {
+ return sDefaultAdjustedLocaleList;
+ }
+ }
+
+ /**
* Also sets the default locale by calling Locale.setDefault() with the first locale in the
* list.
*
@@ -474,6 +525,12 @@ public final class LocaleList implements Parcelable {
Locale.setDefault(sLastDefaultLocale);
sLastExplicitlySetLocaleList = locales;
sDefaultLocaleList = locales;
+ if (localeIndex == 0) {
+ sDefaultAdjustedLocaleList = sDefaultLocaleList;
+ } else {
+ sDefaultAdjustedLocaleList = new LocaleList(
+ sLastDefaultLocale, sDefaultLocaleList);
+ }
}
}
}
diff --git a/core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java b/core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java
deleted file mode 100644
index 55c00314ee63..000000000000
--- a/core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-* Copyright (C) 2015 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.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.DisplayMetrics;
-import android.util.LocaleList;
-
-import java.util.Arrays;
-import java.util.Locale;
-
-public class ResourcesLocaleResolutionTest extends AndroidTestCase {
- @SmallTest
- public void testGetResolvedLocale_englishIsAlwaysConsideredSupported() {
- // First make sure English has no explicit assets other than the default assets
- final AssetManager assets = getContext().getAssets();
- final String supportedLocales[] = assets.getNonSystemLocales();
- for (String languageTag : supportedLocales) {
- if ("en-XA".equals(languageTag)) {
- continue;
- }
- assertFalse(
- "supported locales: " + Arrays.toString(supportedLocales),
- "en".equals(Locale.forLanguageTag(languageTag).getLanguage()));
- }
-
- final DisplayMetrics dm = new DisplayMetrics();
- dm.setToDefaults();
- final Configuration cfg = new Configuration();
- cfg.setToDefaults();
- // Avestan and English have no assets, but Persian does.
- cfg.setLocales(LocaleList.forLanguageTags("ae,en,fa"));
- Resources res = new Resources(assets, dm, cfg);
- // We should get English, because it is always considered supported.
- assertEquals("en", res.getResolvedLocale().toLanguageTag());
- }
-}
-