Merge "Revert "Fix Build: Revert "Implement locale matching in LocalesList."""
diff --git a/api/current.txt b/api/current.txt
index 542695c..1ed2f7e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -38701,9 +38701,9 @@
method public int describeContents();
method public static android.util.LocaleList forLanguageTags(java.lang.String);
method public java.util.Locale get(int);
- method public java.util.Locale getBestMatch(java.lang.String[]);
method public static android.util.LocaleList getDefault();
method public static android.util.LocaleList getEmptyLocaleList();
+ method public java.util.Locale getFirstMatch(java.lang.String[]);
method public java.util.Locale getPrimary();
method public boolean isEmpty();
method public int size();
diff --git a/api/system-current.txt b/api/system-current.txt
index 46e8bc9..b8a379f8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -41034,9 +41034,9 @@
method public int describeContents();
method public static android.util.LocaleList forLanguageTags(java.lang.String);
method public java.util.Locale get(int);
- method public java.util.Locale getBestMatch(java.lang.String[]);
method public static android.util.LocaleList getDefault();
method public static android.util.LocaleList getEmptyLocaleList();
+ method public java.util.Locale getFirstMatch(java.lang.String[]);
method public java.util.Locale getPrimary();
method public boolean isEmpty();
method public int size();
diff --git a/api/test-current.txt b/api/test-current.txt
index b06d4db..fe902bd 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -38703,9 +38703,9 @@
method public int describeContents();
method public static android.util.LocaleList forLanguageTags(java.lang.String);
method public java.util.Locale get(int);
- method public java.util.Locale getBestMatch(java.lang.String[]);
method public static android.util.LocaleList getDefault();
method public static android.util.LocaleList getEmptyLocaleList();
+ method public java.util.Locale getFirstMatch(java.lang.String[]);
method public java.util.Locale getPrimary();
method public boolean isEmpty();
method public int size();
diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java
index b2ee045..1becfb4 100644
--- a/core/java/android/util/LocaleList.java
+++ b/core/java/android/util/LocaleList.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
+import android.icu.util.ULocale;
import android.os.Parcel;
import android.os.Parcelable;
@@ -208,10 +209,66 @@
}
}
+ private static String getLikelyScript(Locale locale) {
+ final String script = locale.getScript();
+ if (!script.isEmpty()) {
+ return script;
+ } else {
+ // TODO: Cache the results if this proves to be too slow
+ return ULocale.addLikelySubtags(ULocale.forLocale(locale)).getScript();
+ }
+ }
+
+ private static int matchScore(Locale supported, Locale desired) {
+ if (supported.equals(desired)) {
+ return 1; // return early so we don't do unnecessary computation
+ }
+ if (!supported.getLanguage().equals(desired.getLanguage())) {
+ return 0;
+ }
+ // There is no match if the two locales use different scripts. This will most imporantly
+ // take care of traditional vs simplified Chinese.
+ final String supportedScr = getLikelyScript(supported);
+ final String desiredScr = getLikelyScript(desired);
+ return supportedScr.equals(desiredScr) ? 1 : 0;
+ }
+
+ /**
+ * Returns the first match in the locale list given an unordered array of supported locales
+ * in BCP47 format.
+ *
+ * If the locale list is empty, null would be returned.
+ */
@Nullable
- public Locale getBestMatch(String[] locales) {
- // TODO: Fix this to actually do locale negotiation and choose the best match
- return getPrimary();
+ public Locale getFirstMatch(String[] supportedLocales) {
+ if (mList.length == 1) { // just one locale, perhaps the most common scenario
+ return mList[0];
+ }
+ if (mList.length == 0) { // empty locale list
+ return null;
+ }
+ // TODO: Figure out what to if en-XA or ar-XB are in the locale list
+ int bestIndex = Integer.MAX_VALUE;
+ for (String tag : supportedLocales) {
+ final Locale supportedLocale = Locale.forLanguageTag(tag);
+ // 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;
+ }
+ }
+ }
+ }
+ if (bestIndex == Integer.MAX_VALUE) { // no match was found
+ return mList[0];
+ } else {
+ return mList[bestIndex];
+ }
}
private final static Object sLock = new Object();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 507233f..e4a6f3c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17901,7 +17901,7 @@
if (mSupportedSystemLocales == null) {
mSupportedSystemLocales = Resources.getSystem().getAssets().getLocales();
}
- final Locale locale = values.getLocales().getBestMatch(mSupportedSystemLocales);
+ final Locale locale = values.getLocales().getFirstMatch(mSupportedSystemLocales);
SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
locale));