diff options
| author | 2015-12-09 01:03:31 +0000 | |
|---|---|---|
| committer | 2015-12-09 01:03:31 +0000 | |
| commit | 7ed26b10e73ee40751f3e20579868d2c8babb0d9 (patch) | |
| tree | 1dc559f36ad449b88d586f7da63f82dde657bcd6 | |
| parent | 58ea989a4ff8ff1ecafcca4c592f3001321e0c8f (diff) | |
| parent | 17b2b2d45854b56de7aa6d1581526e45991274d4 (diff) | |
Merge "Implement locale matching in LocalesList."
| -rw-r--r-- | api/current.txt | 2 | ||||
| -rw-r--r-- | api/system-current.txt | 2 | ||||
| -rw-r--r-- | core/java/android/util/LocaleList.java | 63 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ActivityManagerService.java | 2 |
4 files changed, 63 insertions, 6 deletions
diff --git a/api/current.txt b/api/current.txt index 732a32257a56..19b509d62fb8 100644 --- a/api/current.txt +++ b/api/current.txt @@ -38701,9 +38701,9 @@ package android.util { 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 40347cbfa1ac..dcfc7d11ae12 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -41034,9 +41034,9 @@ package android.util { 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 b2ee045db451..1becfb4a0e23 100644 --- a/core/java/android/util/LocaleList.java +++ b/core/java/android/util/LocaleList.java @@ -19,6 +19,7 @@ package android.util; 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 @@ public final class LocaleList implements Parcelable { } } + 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 507233f4920d..e4a6f3c7c96d 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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)); |