103b2ea1102d9e3e9f189173878706ab04533eea3satok/* 203b2ea1102d9e3e9f189173878706ab04533eea3satok * Copyright (C) 2011 The Android Open Source Project 303b2ea1102d9e3e9f189173878706ab04533eea3satok * 403b2ea1102d9e3e9f189173878706ab04533eea3satok * Licensed under the Apache License, Version 2.0 (the "License"); 503b2ea1102d9e3e9f189173878706ab04533eea3satok * you may not use this file except in compliance with the License. 603b2ea1102d9e3e9f189173878706ab04533eea3satok * You may obtain a copy of the License at 703b2ea1102d9e3e9f189173878706ab04533eea3satok * 803b2ea1102d9e3e9f189173878706ab04533eea3satok * http://www.apache.org/licenses/LICENSE-2.0 903b2ea1102d9e3e9f189173878706ab04533eea3satok * 1003b2ea1102d9e3e9f189173878706ab04533eea3satok * Unless required by applicable law or agreed to in writing, software 1103b2ea1102d9e3e9f189173878706ab04533eea3satok * distributed under the License is distributed on an "AS IS" BASIS, 1203b2ea1102d9e3e9f189173878706ab04533eea3satok * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1303b2ea1102d9e3e9f189173878706ab04533eea3satok * See the License for the specific language governing permissions and 1403b2ea1102d9e3e9f189173878706ab04533eea3satok * limitations under the License. 1503b2ea1102d9e3e9f189173878706ab04533eea3satok */ 1603b2ea1102d9e3e9f189173878706ab04533eea3satok 1703b2ea1102d9e3e9f189173878706ab04533eea3satokpackage android.view.textservice; 1803b2ea1102d9e3e9f189173878706ab04533eea3satok 1903b2ea1102d9e3e9f189173878706ab04533eea3satokimport android.content.Context; 20c714531952fe1c22cae77631aa25dc7441b2b878satokimport android.content.pm.ApplicationInfo; 2103b2ea1102d9e3e9f189173878706ab04533eea3satokimport android.os.Parcel; 2203b2ea1102d9e3e9f189173878706ab04533eea3satokimport android.os.Parcelable; 23c714531952fe1c22cae77631aa25dc7441b2b878satokimport android.text.TextUtils; 240dc1f648a09b46c45190ba1ce7daecf7fada4347satokimport android.util.Slog; 2503b2ea1102d9e3e9f189173878706ab04533eea3satok 2603b2ea1102d9e3e9f189173878706ab04533eea3satokimport java.util.ArrayList; 2703b2ea1102d9e3e9f189173878706ab04533eea3satokimport java.util.Arrays; 280dc1f648a09b46c45190ba1ce7daecf7fada4347satokimport java.util.HashMap; 2903b2ea1102d9e3e9f189173878706ab04533eea3satokimport java.util.HashSet; 3003b2ea1102d9e3e9f189173878706ab04533eea3satokimport java.util.List; 31c714531952fe1c22cae77631aa25dc7441b2b878satokimport java.util.Locale; 3203b2ea1102d9e3e9f189173878706ab04533eea3satok 3303b2ea1102d9e3e9f189173878706ab04533eea3satok/** 3403b2ea1102d9e3e9f189173878706ab04533eea3satok * This class is used to specify meta information of a subtype contained in a spell checker. 3503b2ea1102d9e3e9f189173878706ab04533eea3satok * Subtype can describe locale (e.g. en_US, fr_FR...) used for settings. 3603b2ea1102d9e3e9f189173878706ab04533eea3satok */ 3703b2ea1102d9e3e9f189173878706ab04533eea3satokpublic final class SpellCheckerSubtype implements Parcelable { 380dc1f648a09b46c45190ba1ce7daecf7fada4347satok private static final String TAG = SpellCheckerSubtype.class.getSimpleName(); 390dc1f648a09b46c45190ba1ce7daecf7fada4347satok private static final String EXTRA_VALUE_PAIR_SEPARATOR = ","; 400dc1f648a09b46c45190ba1ce7daecf7fada4347satok private static final String EXTRA_VALUE_KEY_VALUE_SEPARATOR = "="; 4103b2ea1102d9e3e9f189173878706ab04533eea3satok 4203b2ea1102d9e3e9f189173878706ab04533eea3satok private final int mSubtypeHashCode; 4303b2ea1102d9e3e9f189173878706ab04533eea3satok private final int mSubtypeNameResId; 4403b2ea1102d9e3e9f189173878706ab04533eea3satok private final String mSubtypeLocale; 4503b2ea1102d9e3e9f189173878706ab04533eea3satok private final String mSubtypeExtraValue; 460dc1f648a09b46c45190ba1ce7daecf7fada4347satok private HashMap<String, String> mExtraValueHashMapCache; 4703b2ea1102d9e3e9f189173878706ab04533eea3satok 4803b2ea1102d9e3e9f189173878706ab04533eea3satok /** 4903b2ea1102d9e3e9f189173878706ab04533eea3satok * Constructor 5003b2ea1102d9e3e9f189173878706ab04533eea3satok * @param nameId The name of the subtype 5103b2ea1102d9e3e9f189173878706ab04533eea3satok * @param locale The locale supported by the subtype 5203b2ea1102d9e3e9f189173878706ab04533eea3satok * @param extraValue The extra value of the subtype 5303b2ea1102d9e3e9f189173878706ab04533eea3satok */ 5403b2ea1102d9e3e9f189173878706ab04533eea3satok public SpellCheckerSubtype(int nameId, String locale, String extraValue) { 5503b2ea1102d9e3e9f189173878706ab04533eea3satok mSubtypeNameResId = nameId; 5603b2ea1102d9e3e9f189173878706ab04533eea3satok mSubtypeLocale = locale != null ? locale : ""; 5703b2ea1102d9e3e9f189173878706ab04533eea3satok mSubtypeExtraValue = extraValue != null ? extraValue : ""; 5803b2ea1102d9e3e9f189173878706ab04533eea3satok mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeExtraValue); 5903b2ea1102d9e3e9f189173878706ab04533eea3satok } 6003b2ea1102d9e3e9f189173878706ab04533eea3satok 6103b2ea1102d9e3e9f189173878706ab04533eea3satok SpellCheckerSubtype(Parcel source) { 6203b2ea1102d9e3e9f189173878706ab04533eea3satok String s; 6303b2ea1102d9e3e9f189173878706ab04533eea3satok mSubtypeNameResId = source.readInt(); 6403b2ea1102d9e3e9f189173878706ab04533eea3satok s = source.readString(); 6503b2ea1102d9e3e9f189173878706ab04533eea3satok mSubtypeLocale = s != null ? s : ""; 6603b2ea1102d9e3e9f189173878706ab04533eea3satok s = source.readString(); 6703b2ea1102d9e3e9f189173878706ab04533eea3satok mSubtypeExtraValue = s != null ? s : ""; 6803b2ea1102d9e3e9f189173878706ab04533eea3satok mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeExtraValue); 6903b2ea1102d9e3e9f189173878706ab04533eea3satok } 7003b2ea1102d9e3e9f189173878706ab04533eea3satok 7103b2ea1102d9e3e9f189173878706ab04533eea3satok /** 7203b2ea1102d9e3e9f189173878706ab04533eea3satok * @return the name of the subtype 7303b2ea1102d9e3e9f189173878706ab04533eea3satok */ 7403b2ea1102d9e3e9f189173878706ab04533eea3satok public int getNameResId() { 7503b2ea1102d9e3e9f189173878706ab04533eea3satok return mSubtypeNameResId; 7603b2ea1102d9e3e9f189173878706ab04533eea3satok } 7703b2ea1102d9e3e9f189173878706ab04533eea3satok 7803b2ea1102d9e3e9f189173878706ab04533eea3satok /** 7903b2ea1102d9e3e9f189173878706ab04533eea3satok * @return the locale of the subtype 8003b2ea1102d9e3e9f189173878706ab04533eea3satok */ 8103b2ea1102d9e3e9f189173878706ab04533eea3satok public String getLocale() { 8203b2ea1102d9e3e9f189173878706ab04533eea3satok return mSubtypeLocale; 8303b2ea1102d9e3e9f189173878706ab04533eea3satok } 8403b2ea1102d9e3e9f189173878706ab04533eea3satok 8503b2ea1102d9e3e9f189173878706ab04533eea3satok /** 8603b2ea1102d9e3e9f189173878706ab04533eea3satok * @return the extra value of the subtype 8703b2ea1102d9e3e9f189173878706ab04533eea3satok */ 8803b2ea1102d9e3e9f189173878706ab04533eea3satok public String getExtraValue() { 8903b2ea1102d9e3e9f189173878706ab04533eea3satok return mSubtypeExtraValue; 9003b2ea1102d9e3e9f189173878706ab04533eea3satok } 9103b2ea1102d9e3e9f189173878706ab04533eea3satok 920dc1f648a09b46c45190ba1ce7daecf7fada4347satok private HashMap<String, String> getExtraValueHashMap() { 930dc1f648a09b46c45190ba1ce7daecf7fada4347satok if (mExtraValueHashMapCache == null) { 940dc1f648a09b46c45190ba1ce7daecf7fada4347satok mExtraValueHashMapCache = new HashMap<String, String>(); 950dc1f648a09b46c45190ba1ce7daecf7fada4347satok final String[] pairs = mSubtypeExtraValue.split(EXTRA_VALUE_PAIR_SEPARATOR); 960dc1f648a09b46c45190ba1ce7daecf7fada4347satok final int N = pairs.length; 970dc1f648a09b46c45190ba1ce7daecf7fada4347satok for (int i = 0; i < N; ++i) { 980dc1f648a09b46c45190ba1ce7daecf7fada4347satok final String[] pair = pairs[i].split(EXTRA_VALUE_KEY_VALUE_SEPARATOR); 990dc1f648a09b46c45190ba1ce7daecf7fada4347satok if (pair.length == 1) { 1000dc1f648a09b46c45190ba1ce7daecf7fada4347satok mExtraValueHashMapCache.put(pair[0], null); 1010dc1f648a09b46c45190ba1ce7daecf7fada4347satok } else if (pair.length > 1) { 1020dc1f648a09b46c45190ba1ce7daecf7fada4347satok if (pair.length > 2) { 1030dc1f648a09b46c45190ba1ce7daecf7fada4347satok Slog.w(TAG, "ExtraValue has two or more '='s"); 1040dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 1050dc1f648a09b46c45190ba1ce7daecf7fada4347satok mExtraValueHashMapCache.put(pair[0], pair[1]); 1060dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 1070dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 1080dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 1090dc1f648a09b46c45190ba1ce7daecf7fada4347satok return mExtraValueHashMapCache; 1100dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 1110dc1f648a09b46c45190ba1ce7daecf7fada4347satok 1120dc1f648a09b46c45190ba1ce7daecf7fada4347satok /** 1130dc1f648a09b46c45190ba1ce7daecf7fada4347satok * The string of ExtraValue in subtype should be defined as follows: 1140dc1f648a09b46c45190ba1ce7daecf7fada4347satok * example: key0,key1=value1,key2,key3,key4=value4 1150dc1f648a09b46c45190ba1ce7daecf7fada4347satok * @param key the key of extra value 1160dc1f648a09b46c45190ba1ce7daecf7fada4347satok * @return the subtype contains specified the extra value 1170dc1f648a09b46c45190ba1ce7daecf7fada4347satok */ 1180dc1f648a09b46c45190ba1ce7daecf7fada4347satok public boolean containsExtraValueKey(String key) { 1190dc1f648a09b46c45190ba1ce7daecf7fada4347satok return getExtraValueHashMap().containsKey(key); 1200dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 1210dc1f648a09b46c45190ba1ce7daecf7fada4347satok 1220dc1f648a09b46c45190ba1ce7daecf7fada4347satok /** 1230dc1f648a09b46c45190ba1ce7daecf7fada4347satok * The string of ExtraValue in subtype should be defined as follows: 1240dc1f648a09b46c45190ba1ce7daecf7fada4347satok * example: key0,key1=value1,key2,key3,key4=value4 1250dc1f648a09b46c45190ba1ce7daecf7fada4347satok * @param key the key of extra value 1260dc1f648a09b46c45190ba1ce7daecf7fada4347satok * @return the value of the specified key 1270dc1f648a09b46c45190ba1ce7daecf7fada4347satok */ 1280dc1f648a09b46c45190ba1ce7daecf7fada4347satok public String getExtraValueOf(String key) { 1290dc1f648a09b46c45190ba1ce7daecf7fada4347satok return getExtraValueHashMap().get(key); 1300dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 1310dc1f648a09b46c45190ba1ce7daecf7fada4347satok 13203b2ea1102d9e3e9f189173878706ab04533eea3satok @Override 13303b2ea1102d9e3e9f189173878706ab04533eea3satok public int hashCode() { 13403b2ea1102d9e3e9f189173878706ab04533eea3satok return mSubtypeHashCode; 13503b2ea1102d9e3e9f189173878706ab04533eea3satok } 13603b2ea1102d9e3e9f189173878706ab04533eea3satok 13703b2ea1102d9e3e9f189173878706ab04533eea3satok @Override 13803b2ea1102d9e3e9f189173878706ab04533eea3satok public boolean equals(Object o) { 13903b2ea1102d9e3e9f189173878706ab04533eea3satok if (o instanceof SpellCheckerSubtype) { 14003b2ea1102d9e3e9f189173878706ab04533eea3satok SpellCheckerSubtype subtype = (SpellCheckerSubtype) o; 14103b2ea1102d9e3e9f189173878706ab04533eea3satok return (subtype.hashCode() == hashCode()) 14203b2ea1102d9e3e9f189173878706ab04533eea3satok && (subtype.getNameResId() == getNameResId()) 14303b2ea1102d9e3e9f189173878706ab04533eea3satok && (subtype.getLocale().equals(getLocale())) 14403b2ea1102d9e3e9f189173878706ab04533eea3satok && (subtype.getExtraValue().equals(getExtraValue())); 14503b2ea1102d9e3e9f189173878706ab04533eea3satok } 14603b2ea1102d9e3e9f189173878706ab04533eea3satok return false; 14703b2ea1102d9e3e9f189173878706ab04533eea3satok } 14803b2ea1102d9e3e9f189173878706ab04533eea3satok 149f927e17ae543b6edeae8200cc86c59c3ee740670satok /** 150f927e17ae543b6edeae8200cc86c59c3ee740670satok * @hide 151f927e17ae543b6edeae8200cc86c59c3ee740670satok */ 152f927e17ae543b6edeae8200cc86c59c3ee740670satok public static Locale constructLocaleFromString(String localeStr) { 153c714531952fe1c22cae77631aa25dc7441b2b878satok if (TextUtils.isEmpty(localeStr)) 154c714531952fe1c22cae77631aa25dc7441b2b878satok return null; 155c714531952fe1c22cae77631aa25dc7441b2b878satok String[] localeParams = localeStr.split("_", 3); 156c714531952fe1c22cae77631aa25dc7441b2b878satok // The length of localeStr is guaranteed to always return a 1 <= value <= 3 157c714531952fe1c22cae77631aa25dc7441b2b878satok // because localeStr is not empty. 158c714531952fe1c22cae77631aa25dc7441b2b878satok if (localeParams.length == 1) { 159c714531952fe1c22cae77631aa25dc7441b2b878satok return new Locale(localeParams[0]); 160c714531952fe1c22cae77631aa25dc7441b2b878satok } else if (localeParams.length == 2) { 161c714531952fe1c22cae77631aa25dc7441b2b878satok return new Locale(localeParams[0], localeParams[1]); 162c714531952fe1c22cae77631aa25dc7441b2b878satok } else if (localeParams.length == 3) { 163c714531952fe1c22cae77631aa25dc7441b2b878satok return new Locale(localeParams[0], localeParams[1], localeParams[2]); 164c714531952fe1c22cae77631aa25dc7441b2b878satok } 165c714531952fe1c22cae77631aa25dc7441b2b878satok return null; 166c714531952fe1c22cae77631aa25dc7441b2b878satok } 167c714531952fe1c22cae77631aa25dc7441b2b878satok 168c714531952fe1c22cae77631aa25dc7441b2b878satok /** 169c714531952fe1c22cae77631aa25dc7441b2b878satok * @param context Context will be used for getting Locale and PackageManager. 170c714531952fe1c22cae77631aa25dc7441b2b878satok * @param packageName The package name of the spell checker 171c714531952fe1c22cae77631aa25dc7441b2b878satok * @param appInfo The application info of the spell checker 172c714531952fe1c22cae77631aa25dc7441b2b878satok * @return a display name for this subtype. The string resource of the label (mSubtypeNameResId) 173c714531952fe1c22cae77631aa25dc7441b2b878satok * can have only one %s in it. If there is, the %s part will be replaced with the locale's 174c714531952fe1c22cae77631aa25dc7441b2b878satok * display name by the formatter. If there is not, this method simply returns the string 175c714531952fe1c22cae77631aa25dc7441b2b878satok * specified by mSubtypeNameResId. If mSubtypeNameResId is not specified (== 0), it's up to the 176c714531952fe1c22cae77631aa25dc7441b2b878satok * framework to generate an appropriate display name. 177c714531952fe1c22cae77631aa25dc7441b2b878satok */ 178c714531952fe1c22cae77631aa25dc7441b2b878satok public CharSequence getDisplayName( 179c714531952fe1c22cae77631aa25dc7441b2b878satok Context context, String packageName, ApplicationInfo appInfo) { 180c714531952fe1c22cae77631aa25dc7441b2b878satok final Locale locale = constructLocaleFromString(mSubtypeLocale); 181c714531952fe1c22cae77631aa25dc7441b2b878satok final String localeStr = locale != null ? locale.getDisplayName() : mSubtypeLocale; 182c714531952fe1c22cae77631aa25dc7441b2b878satok if (mSubtypeNameResId == 0) { 183c714531952fe1c22cae77631aa25dc7441b2b878satok return localeStr; 184c714531952fe1c22cae77631aa25dc7441b2b878satok } 185c714531952fe1c22cae77631aa25dc7441b2b878satok final CharSequence subtypeName = context.getPackageManager().getText( 186c714531952fe1c22cae77631aa25dc7441b2b878satok packageName, mSubtypeNameResId, appInfo); 187c714531952fe1c22cae77631aa25dc7441b2b878satok if (!TextUtils.isEmpty(subtypeName)) { 188c714531952fe1c22cae77631aa25dc7441b2b878satok return String.format(subtypeName.toString(), localeStr); 189c714531952fe1c22cae77631aa25dc7441b2b878satok } else { 190c714531952fe1c22cae77631aa25dc7441b2b878satok return localeStr; 191c714531952fe1c22cae77631aa25dc7441b2b878satok } 192c714531952fe1c22cae77631aa25dc7441b2b878satok } 193c714531952fe1c22cae77631aa25dc7441b2b878satok 19403b2ea1102d9e3e9f189173878706ab04533eea3satok @Override 19503b2ea1102d9e3e9f189173878706ab04533eea3satok public int describeContents() { 19603b2ea1102d9e3e9f189173878706ab04533eea3satok return 0; 19703b2ea1102d9e3e9f189173878706ab04533eea3satok } 19803b2ea1102d9e3e9f189173878706ab04533eea3satok 19903b2ea1102d9e3e9f189173878706ab04533eea3satok @Override 20003b2ea1102d9e3e9f189173878706ab04533eea3satok public void writeToParcel(Parcel dest, int parcelableFlags) { 20103b2ea1102d9e3e9f189173878706ab04533eea3satok dest.writeInt(mSubtypeNameResId); 20203b2ea1102d9e3e9f189173878706ab04533eea3satok dest.writeString(mSubtypeLocale); 20303b2ea1102d9e3e9f189173878706ab04533eea3satok dest.writeString(mSubtypeExtraValue); 20403b2ea1102d9e3e9f189173878706ab04533eea3satok } 20503b2ea1102d9e3e9f189173878706ab04533eea3satok 20603b2ea1102d9e3e9f189173878706ab04533eea3satok public static final Parcelable.Creator<SpellCheckerSubtype> CREATOR 20703b2ea1102d9e3e9f189173878706ab04533eea3satok = new Parcelable.Creator<SpellCheckerSubtype>() { 20803b2ea1102d9e3e9f189173878706ab04533eea3satok @Override 20903b2ea1102d9e3e9f189173878706ab04533eea3satok public SpellCheckerSubtype createFromParcel(Parcel source) { 21003b2ea1102d9e3e9f189173878706ab04533eea3satok return new SpellCheckerSubtype(source); 21103b2ea1102d9e3e9f189173878706ab04533eea3satok } 21203b2ea1102d9e3e9f189173878706ab04533eea3satok 21303b2ea1102d9e3e9f189173878706ab04533eea3satok @Override 21403b2ea1102d9e3e9f189173878706ab04533eea3satok public SpellCheckerSubtype[] newArray(int size) { 21503b2ea1102d9e3e9f189173878706ab04533eea3satok return new SpellCheckerSubtype[size]; 21603b2ea1102d9e3e9f189173878706ab04533eea3satok } 21703b2ea1102d9e3e9f189173878706ab04533eea3satok }; 21803b2ea1102d9e3e9f189173878706ab04533eea3satok 21903b2ea1102d9e3e9f189173878706ab04533eea3satok private static int hashCodeInternal(String locale, String extraValue) { 22003b2ea1102d9e3e9f189173878706ab04533eea3satok return Arrays.hashCode(new Object[] {locale, extraValue}); 22103b2ea1102d9e3e9f189173878706ab04533eea3satok } 22203b2ea1102d9e3e9f189173878706ab04533eea3satok 22303b2ea1102d9e3e9f189173878706ab04533eea3satok /** 22403b2ea1102d9e3e9f189173878706ab04533eea3satok * Sort the list of subtypes 22503b2ea1102d9e3e9f189173878706ab04533eea3satok * @param context Context will be used for getting localized strings 22603b2ea1102d9e3e9f189173878706ab04533eea3satok * @param flags Flags for the sort order 22703b2ea1102d9e3e9f189173878706ab04533eea3satok * @param sci SpellCheckerInfo of which subtypes are subject to be sorted 22803b2ea1102d9e3e9f189173878706ab04533eea3satok * @param subtypeList List which will be sorted 22903b2ea1102d9e3e9f189173878706ab04533eea3satok * @return Sorted list of subtypes 23003b2ea1102d9e3e9f189173878706ab04533eea3satok * @hide 23103b2ea1102d9e3e9f189173878706ab04533eea3satok */ 23203b2ea1102d9e3e9f189173878706ab04533eea3satok public static List<SpellCheckerSubtype> sort(Context context, int flags, SpellCheckerInfo sci, 23303b2ea1102d9e3e9f189173878706ab04533eea3satok List<SpellCheckerSubtype> subtypeList) { 23403b2ea1102d9e3e9f189173878706ab04533eea3satok if (sci == null) return subtypeList; 23503b2ea1102d9e3e9f189173878706ab04533eea3satok final HashSet<SpellCheckerSubtype> subtypesSet = new HashSet<SpellCheckerSubtype>( 23603b2ea1102d9e3e9f189173878706ab04533eea3satok subtypeList); 23703b2ea1102d9e3e9f189173878706ab04533eea3satok final ArrayList<SpellCheckerSubtype> sortedList = new ArrayList<SpellCheckerSubtype>(); 23803b2ea1102d9e3e9f189173878706ab04533eea3satok int N = sci.getSubtypeCount(); 23903b2ea1102d9e3e9f189173878706ab04533eea3satok for (int i = 0; i < N; ++i) { 24003b2ea1102d9e3e9f189173878706ab04533eea3satok SpellCheckerSubtype subtype = sci.getSubtypeAt(i); 24103b2ea1102d9e3e9f189173878706ab04533eea3satok if (subtypesSet.contains(subtype)) { 24203b2ea1102d9e3e9f189173878706ab04533eea3satok sortedList.add(subtype); 24303b2ea1102d9e3e9f189173878706ab04533eea3satok subtypesSet.remove(subtype); 24403b2ea1102d9e3e9f189173878706ab04533eea3satok } 24503b2ea1102d9e3e9f189173878706ab04533eea3satok } 24603b2ea1102d9e3e9f189173878706ab04533eea3satok // If subtypes in subtypesSet remain, that means these subtypes are not 24703b2ea1102d9e3e9f189173878706ab04533eea3satok // contained in sci, so the remaining subtypes will be appended. 24803b2ea1102d9e3e9f189173878706ab04533eea3satok for (SpellCheckerSubtype subtype: subtypesSet) { 24903b2ea1102d9e3e9f189173878706ab04533eea3satok sortedList.add(subtype); 25003b2ea1102d9e3e9f189173878706ab04533eea3satok } 25103b2ea1102d9e3e9f189173878706ab04533eea3satok return sortedList; 25203b2ea1102d9e3e9f189173878706ab04533eea3satok } 25303b2ea1102d9e3e9f189173878706ab04533eea3satok} 254