1 /* 2 * Copyright (C) 2008-2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package com.android.inputmethod.deprecated.languageswitcher; 18 19 import com.android.inputmethod.compat.SharedPreferencesCompat; 20 import com.android.inputmethod.keyboard.internal.KeyboardBuilder; 21 import com.android.inputmethod.latin.DictionaryFactory; 22 import com.android.inputmethod.latin.LocaleUtils; 23 import com.android.inputmethod.latin.R; 24 import com.android.inputmethod.latin.Settings; 25 import com.android.inputmethod.latin.Utils; 26 27 import org.xmlpull.v1.XmlPullParserException; 28 29 import android.content.SharedPreferences; 30 import android.content.SharedPreferences.Editor; 31 import android.content.res.Resources; 32 import android.os.Bundle; 33 import android.preference.CheckBoxPreference; 34 import android.preference.PreferenceActivity; 35 import android.preference.PreferenceGroup; 36 import android.preference.PreferenceManager; 37 import android.text.TextUtils; 38 import android.util.Pair; 39 40 import java.io.IOException; 41 import java.text.Collator; 42 import java.util.ArrayList; 43 import java.util.Arrays; 44 import java.util.HashMap; 45 import java.util.Locale; 46 import java.util.Map.Entry; 47 import java.util.TreeMap; 48 49 public class InputLanguageSelection extends PreferenceActivity { 50 51 private SharedPreferences mPrefs; 52 private String mSelectedLanguages; 53 private HashMap<CheckBoxPreference, Locale> mLocaleMap = 54 new HashMap<CheckBoxPreference, Locale>(); 55 56 private static class LocaleEntry implements Comparable<Object> { 57 private static Collator sCollator = Collator.getInstance(); 58 59 private String mLabel; 60 public final Locale mLocale; 61 62 public LocaleEntry(String label, Locale locale) { 63 this.mLabel = label; 64 this.mLocale = locale; 65 } 66 67 @Override 68 public String toString() { 69 return this.mLabel; 70 } 71 72 @Override 73 public int compareTo(Object o) { 74 return sCollator.compare(this.mLabel, ((LocaleEntry) o).mLabel); 75 } 76 } 77 78 @Override 79 protected void onCreate(Bundle icicle) { 80 super.onCreate(icicle); 81 addPreferencesFromResource(R.xml.language_prefs); 82 // Get the settings preferences 83 mPrefs = PreferenceManager.getDefaultSharedPreferences(this); 84 mSelectedLanguages = mPrefs.getString(Settings.PREF_SELECTED_LANGUAGES, ""); 85 String[] languageList = mSelectedLanguages.split(","); 86 ArrayList<LocaleEntry> availableLanguages = getUniqueLocales(); 87 PreferenceGroup parent = getPreferenceScreen(); 88 final HashMap<Long, LocaleEntry> dictionaryIdLocaleMap = new HashMap<Long, LocaleEntry>(); 89 final TreeMap<LocaleEntry, Boolean> localeHasDictionaryMap = 90 new TreeMap<LocaleEntry, Boolean>(); 91 for (int i = 0; i < availableLanguages.size(); i++) { 92 LocaleEntry loc = availableLanguages.get(i); 93 Locale locale = loc.mLocale; 94 final Pair<Long, Boolean> hasDictionaryOrLayout = hasDictionaryOrLayout(locale); 95 final Long dictionaryId = hasDictionaryOrLayout.first; 96 final boolean hasLayout = hasDictionaryOrLayout.second; 97 final boolean hasDictionary = dictionaryId != null; 98 // Add this locale to the supported list if: 99 // 1) this locale has a layout/ 2) this locale has a dictionary 100 // If some locales have no layout but have a same dictionary, the shortest locale 101 // will be added to the supported list. 102 if (!hasLayout && !hasDictionary) { 103 continue; 104 } 105 if (hasLayout) { 106 localeHasDictionaryMap.put(loc, hasDictionary); 107 } 108 if (!hasDictionary) { 109 continue; 110 } 111 if (dictionaryIdLocaleMap.containsKey(dictionaryId)) { 112 final String newLocale = locale.toString(); 113 final String oldLocale = 114 dictionaryIdLocaleMap.get(dictionaryId).mLocale.toString(); 115 // Check if this locale is more appropriate to be the candidate of the input locale. 116 if (oldLocale.length() <= newLocale.length() && !hasLayout) { 117 // Don't add this new locale to the map<dictionary id, locale> if: 118 // 1) the new locale's name is longer than the existing one, and 119 // 2) the new locale doesn't have its layout 120 continue; 121 } 122 } 123 dictionaryIdLocaleMap.put(dictionaryId, loc); 124 } 125 126 for (LocaleEntry localeEntry : dictionaryIdLocaleMap.values()) { 127 if (!localeHasDictionaryMap.containsKey(localeEntry)) { 128 localeHasDictionaryMap.put(localeEntry, true); 129 } 130 } 131 132 for (Entry<LocaleEntry, Boolean> entry : localeHasDictionaryMap.entrySet()) { 133 final LocaleEntry localeEntry = entry.getKey(); 134 final Locale locale = localeEntry.mLocale; 135 final Boolean hasDictionary = entry.getValue(); 136 CheckBoxPreference pref = new CheckBoxPreference(this); 137 pref.setTitle(localeEntry.mLabel); 138 boolean checked = isLocaleIn(locale, languageList); 139 pref.setChecked(checked); 140 if (hasDictionary) { 141 pref.setSummary(R.string.has_dictionary); 142 } 143 mLocaleMap.put(pref, locale); 144 parent.addPreference(pref); 145 } 146 } 147 148 private boolean isLocaleIn(Locale locale, String[] list) { 149 String lang = get5Code(locale); 150 for (int i = 0; i < list.length; i++) { 151 if (lang.equalsIgnoreCase(list[i])) return true; 152 } 153 return false; 154 } 155 156 private Pair<Long, Boolean> hasDictionaryOrLayout(Locale locale) { 157 if (locale == null) return new Pair<Long, Boolean>(null, false); 158 final Resources res = getResources(); 159 final Locale saveLocale = LocaleUtils.setSystemLocale(res, locale); 160 final Long dictionaryId = DictionaryFactory.getDictionaryId(this, locale); 161 boolean hasLayout = false; 162 163 try { 164 final String localeStr = locale.toString(); 165 final String[] layoutCountryCodes = KeyboardBuilder.parseKeyboardLocale( 166 this, R.xml.kbd_qwerty).split(",", -1); 167 if (!TextUtils.isEmpty(localeStr) && layoutCountryCodes.length > 0) { 168 for (String s : layoutCountryCodes) { 169 if (s.equals(localeStr)) { 170 hasLayout = true; 171 break; 172 } 173 } 174 } 175 } catch (XmlPullParserException e) { 176 } catch (IOException e) { 177 } 178 LocaleUtils.setSystemLocale(res, saveLocale); 179 return new Pair<Long, Boolean>(dictionaryId, hasLayout); 180 } 181 182 private String get5Code(Locale locale) { 183 String country = locale.getCountry(); 184 return locale.getLanguage() 185 + (TextUtils.isEmpty(country) ? "" : "_" + country); 186 } 187 188 @Override 189 protected void onResume() { 190 super.onResume(); 191 } 192 193 @Override 194 protected void onPause() { 195 super.onPause(); 196 // Save the selected languages 197 String checkedLanguages = ""; 198 PreferenceGroup parent = getPreferenceScreen(); 199 int count = parent.getPreferenceCount(); 200 for (int i = 0; i < count; i++) { 201 CheckBoxPreference pref = (CheckBoxPreference) parent.getPreference(i); 202 if (pref.isChecked()) { 203 checkedLanguages += get5Code(mLocaleMap.get(pref)) + ","; 204 } 205 } 206 if (checkedLanguages.length() < 1) checkedLanguages = null; // Save null 207 Editor editor = mPrefs.edit(); 208 editor.putString(Settings.PREF_SELECTED_LANGUAGES, checkedLanguages); 209 SharedPreferencesCompat.apply(editor); 210 } 211 212 public ArrayList<LocaleEntry> getUniqueLocales() { 213 String[] locales = getAssets().getLocales(); 214 Arrays.sort(locales); 215 ArrayList<LocaleEntry> uniqueLocales = new ArrayList<LocaleEntry>(); 216 217 final int origSize = locales.length; 218 LocaleEntry[] preprocess = new LocaleEntry[origSize]; 219 int finalSize = 0; 220 for (int i = 0 ; i < origSize; i++ ) { 221 String s = locales[i]; 222 int len = s.length(); 223 String language = ""; 224 String country = ""; 225 if (len == 5) { 226 language = s.substring(0, 2); 227 country = s.substring(3, 5); 228 } else if (len < 5) { 229 language = s; 230 } 231 Locale l = new Locale(language, country); 232 233 // Exclude languages that are not relevant to LatinIME 234 if (TextUtils.isEmpty(language)) { 235 continue; 236 } 237 238 if (finalSize == 0) { 239 preprocess[finalSize++] = 240 new LocaleEntry(Utils.getFullDisplayName(l, false), l); 241 } else { 242 if (s.equals("zz_ZZ")) { 243 // ignore this locale 244 } else { 245 final String displayName = Utils.getFullDisplayName(l, false); 246 preprocess[finalSize++] = new LocaleEntry(displayName, l); 247 } 248 } 249 } 250 for (int i = 0; i < finalSize ; i++) { 251 uniqueLocales.add(preprocess[i]); 252 } 253 return uniqueLocales; 254 } 255 } 256