From cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Thu, 8 Mar 2012 17:07:02 +0900 Subject: Split Utils class to StringUtils, SubtypeUtils, and JniUtils Change-Id: I09e91675fe7d573dad8c933ad513b21d7e409144 --- .../com/android/inputmethod/latin/StringUtils.java | 198 +++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 java/src/com/android/inputmethod/latin/StringUtils.java (limited to 'java/src/com/android/inputmethod/latin/StringUtils.java') diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java new file mode 100644 index 000000000..81c3b4edf --- /dev/null +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2012 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 com.android.inputmethod.latin; + +import android.text.TextUtils; +import android.view.inputmethod.EditorInfo; + +import com.android.inputmethod.keyboard.Keyboard; + +import java.util.ArrayList; +import java.util.Locale; + +public class StringUtils { + private StringUtils() { + // This utility class is not publicly instantiable. + } + + public static boolean canBeFollowedByPeriod(final int codePoint) { + // TODO: Check again whether there really ain't a better way to check this. + // TODO: This should probably be language-dependant... + return Character.isLetterOrDigit(codePoint) + || codePoint == Keyboard.CODE_SINGLE_QUOTE + || codePoint == Keyboard.CODE_DOUBLE_QUOTE + || codePoint == Keyboard.CODE_CLOSING_PARENTHESIS + || codePoint == Keyboard.CODE_CLOSING_SQUARE_BRACKET + || codePoint == Keyboard.CODE_CLOSING_CURLY_BRACKET + || codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET; + } + + public static int codePointCount(String text) { + if (TextUtils.isEmpty(text)) return 0; + return text.codePointCount(0, text.length()); + } + + public static boolean containsInCsv(String key, String csv) { + if (csv == null) + return false; + for (String option : csv.split(",")) { + if (option.equals(key)) + return true; + } + return false; + } + + public static boolean inPrivateImeOptions(String packageName, String key, + EditorInfo editorInfo) { + if (editorInfo == null) + return false; + return containsInCsv(packageName != null ? packageName + "." + key : key, + editorInfo.privateImeOptions); + } + + /** + * Returns true if a and b are equal ignoring the case of the character. + * @param a first character to check + * @param b second character to check + * @return {@code true} if a and b are equal, {@code false} otherwise. + */ + public static boolean equalsIgnoreCase(char a, char b) { + // Some language, such as Turkish, need testing both cases. + return a == b + || Character.toLowerCase(a) == Character.toLowerCase(b) + || Character.toUpperCase(a) == Character.toUpperCase(b); + } + + /** + * Returns true if a and b are equal ignoring the case of the characters, including if they are + * both null. + * @param a first CharSequence to check + * @param b second CharSequence to check + * @return {@code true} if a and b are equal, {@code false} otherwise. + */ + public static boolean equalsIgnoreCase(CharSequence a, CharSequence b) { + if (a == b) + return true; // including both a and b are null. + if (a == null || b == null) + return false; + final int length = a.length(); + if (length != b.length()) + return false; + for (int i = 0; i < length; i++) { + if (!equalsIgnoreCase(a.charAt(i), b.charAt(i))) + return false; + } + return true; + } + + /** + * Returns true if a and b are equal ignoring the case of the characters, including if a is null + * and b is zero length. + * @param a CharSequence to check + * @param b character array to check + * @param offset start offset of array b + * @param length length of characters in array b + * @return {@code true} if a and b are equal, {@code false} otherwise. + * @throws IndexOutOfBoundsException + * if {@code offset < 0 || length < 0 || offset + length > data.length}. + * @throws NullPointerException if {@code b == null}. + */ + public static boolean equalsIgnoreCase(CharSequence a, char[] b, int offset, int length) { + if (offset < 0 || length < 0 || length > b.length - offset) + throw new IndexOutOfBoundsException("array.length=" + b.length + " offset=" + offset + + " length=" + length); + if (a == null) + return length == 0; // including a is null and b is zero length. + if (a.length() != length) + return false; + for (int i = 0; i < length; i++) { + if (!equalsIgnoreCase(a.charAt(i), b[offset + i])) + return false; + } + return true; + } + + /** + * Remove duplicates from an array of strings. + * + * This method will always keep the first occurence of all strings at their position + * in the array, removing the subsequent ones. + */ + public static void removeDupes(final ArrayList suggestions) { + if (suggestions.size() < 2) return; + int i = 1; + // Don't cache suggestions.size(), since we may be removing items + while (i < suggestions.size()) { + final CharSequence cur = suggestions.get(i); + // Compare each suggestion with each previous suggestion + for (int j = 0; j < i; j++) { + CharSequence previous = suggestions.get(j); + if (TextUtils.equals(cur, previous)) { + removeFromSuggestions(suggestions, i); + i--; + break; + } + } + i++; + } + } + + private static void removeFromSuggestions(final ArrayList suggestions, + final int index) { + final CharSequence garbage = suggestions.remove(index); + if (garbage instanceof StringBuilder) { + StringBuilderPool.recycle((StringBuilder)garbage); + } + } + + public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) { + if (returnsNameInThisLocale) { + return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale); + } else { + return toTitleCase(locale.getDisplayName(), locale); + } + } + + public static String getDisplayLanguage(Locale locale) { + return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale); + } + + public static String getMiddleDisplayLanguage(Locale locale) { + return toTitleCase((LocaleUtils.constructLocaleFromString( + locale.getLanguage()).getDisplayLanguage(locale)), locale); + } + + public static String getShortDisplayLanguage(Locale locale) { + return toTitleCase(locale.getLanguage(), locale); + } + + public static String toTitleCase(String s, Locale locale) { + if (s.length() <= 1) { + // TODO: is this really correct? Shouldn't this be s.toUpperCase()? + return s; + } + // TODO: fix the bugs below + // - This does not work for Greek, because it returns upper case instead of title case. + // - It does not work for Serbian, because it fails to account for the "lj" character, + // which should be "Lj" in title case and "LJ" in upper case. + // - It does not work for Dutch, because it fails to account for the "ij" digraph, which + // are two different characters but both should be capitalized as "IJ" as if they were + // a single letter. + // - It also does not work with unicode surrogate code points. + return s.toUpperCase(locale).charAt(0) + s.substring(1); + } +} -- cgit v1.2.3-83-g751a From adf218eed544f2239ca5394b8a6bcc542d89a4d9 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 13 Mar 2012 16:52:42 +0900 Subject: Kill the StringBuilderPool. The intention may have been nice originally but these end up being copied anyway :/ Let's remove them now, and in a later change, just keep references to the created objects. Change-Id: Ifba8357c20384f9eb40cd916665ed1fc6dc8cab1 --- .../inputmethod/latin/StringBuilderPool.java | 70 ---------------------- .../com/android/inputmethod/latin/StringUtils.java | 10 +--- .../src/com/android/inputmethod/latin/Suggest.java | 48 ++++----------- 3 files changed, 11 insertions(+), 117 deletions(-) delete mode 100644 java/src/com/android/inputmethod/latin/StringBuilderPool.java (limited to 'java/src/com/android/inputmethod/latin/StringUtils.java') diff --git a/java/src/com/android/inputmethod/latin/StringBuilderPool.java b/java/src/com/android/inputmethod/latin/StringBuilderPool.java deleted file mode 100644 index a663ed43e..000000000 --- a/java/src/com/android/inputmethod/latin/StringBuilderPool.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.inputmethod.latin; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * A pool of string builders to be used from anywhere. - */ -public class StringBuilderPool { - // Singleton - private static final StringBuilderPool sInstance = new StringBuilderPool(); - private static final boolean DEBUG = false; - private StringBuilderPool() {} - // TODO: Make this a normal array with a size of 20, or a ConcurrentQueue - private final List mPool = - Collections.synchronizedList(new ArrayList()); - - public static StringBuilder getStringBuilder(final int initialSize) { - // TODO: although the pool is synchronized, the following is not thread-safe. - // Two threads entering this at the same time could take the same size of the pool and the - // second to attempt removing this index from the pool would crash with an - // IndexOutOfBoundsException. - // At the moment this pool is only used in Suggest.java and only in one thread so it's - // okay. The simplest thing to do here is probably to replace the ArrayList with a - // ConcurrentQueue. - final int poolSize = sInstance.mPool.size(); - final StringBuilder sb = poolSize > 0 ? (StringBuilder) sInstance.mPool.remove(poolSize - 1) - : new StringBuilder(initialSize); - sb.setLength(0); - return sb; - } - - public static void recycle(final StringBuilder garbage) { - if (DEBUG) { - final int gid = garbage.hashCode(); - for (final StringBuilder q : sInstance.mPool) { - if (gid == q.hashCode()) throw new RuntimeException("Duplicate id " + gid); - } - } - sInstance.mPool.add(garbage); - } - - public static void ensureCapacity(final int capacity, final int initialSize) { - for (int i = sInstance.mPool.size(); i < capacity; ++i) { - final StringBuilder sb = new StringBuilder(initialSize); - sInstance.mPool.add(sb); - } - } - - public static int getSize() { - return sInstance.mPool.size(); - } -} diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index 81c3b4edf..7b34cae63 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -142,7 +142,7 @@ public class StringUtils { for (int j = 0; j < i; j++) { CharSequence previous = suggestions.get(j); if (TextUtils.equals(cur, previous)) { - removeFromSuggestions(suggestions, i); + suggestions.remove(i); i--; break; } @@ -151,14 +151,6 @@ public class StringUtils { } } - private static void removeFromSuggestions(final ArrayList suggestions, - final int index) { - final CharSequence garbage = suggestions.remove(index); - if (garbage instanceof StringBuilder) { - StringBuilderPool.recycle((StringBuilder)garbage); - } - } - public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) { if (returnsNameInThisLocale) { return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale); diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index e04a4e8d1..f0bd7b13c 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -98,7 +98,7 @@ public class Suggest implements Dictionary.WordCallback { private int[] mBigramScores = new int[PREF_MAX_BIGRAMS]; private ArrayList mSuggestions = new ArrayList(); - ArrayList mBigramSuggestions = new ArrayList(); + private ArrayList mBigramSuggestions = new ArrayList(); private CharSequence mConsideredWord; // TODO: Remove these member variables by passing more context to addWord() callback method @@ -122,7 +122,6 @@ public class Suggest implements Dictionary.WordCallback { private void initWhitelistAndAutocorrectAndPool(final Context context, final Locale locale) { mWhiteListDictionary = new WhitelistDictionary(context, locale); addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_WHITELIST, mWhiteListDictionary); - StringBuilderPool.ensureCapacity(mPrefMaxSuggestions, getApproxMaxWordLength()); } private void initAsynchronously(final Context context, final int dictionaryResId, @@ -229,14 +228,13 @@ public class Suggest implements Dictionary.WordCallback { mPrefMaxSuggestions = maxSuggestions; mScores = new int[mPrefMaxSuggestions]; mBigramScores = new int[PREF_MAX_BIGRAMS]; - collectGarbage(mSuggestions, mPrefMaxSuggestions); - StringBuilderPool.ensureCapacity(mPrefMaxSuggestions, getApproxMaxWordLength()); + mSuggestions = new ArrayList(mPrefMaxSuggestions); } private CharSequence capitalizeWord(boolean all, boolean first, CharSequence word) { if (TextUtils.isEmpty(word) || !(all || first)) return word; final int wordLength = word.length(); - final StringBuilder sb = StringBuilderPool.getStringBuilder(getApproxMaxWordLength()); + final StringBuilder sb = new StringBuilder(getApproxMaxWordLength()); // TODO: Must pay attention to locale when changing case. if (all) { sb.append(word.toString().toUpperCase()); @@ -250,12 +248,7 @@ public class Suggest implements Dictionary.WordCallback { } protected void addBigramToSuggestions(CharSequence bigram) { - // TODO: Try to be a little more shrewd with resource allocation. - // At the moment we copy this object because the StringBuilders are pooled (see - // StringBuilderPool.java) and when we are finished using mSuggestions and - // mBigramSuggestions we will take everything from both and insert them back in the - // pool, so we can't allow the same object to be in both lists at the same time. - final StringBuilder sb = StringBuilderPool.getStringBuilder(getApproxMaxWordLength()); + final StringBuilder sb = new StringBuilder(getApproxMaxWordLength()); sb.append(bigram); mSuggestions.add(sb); } @@ -266,7 +259,7 @@ public class Suggest implements Dictionary.WordCallback { mIsFirstCharCapitalized = false; mIsAllUpperCase = false; mTrailingSingleQuotesCount = 0; - collectGarbage(mSuggestions, mPrefMaxSuggestions); + mSuggestions = new ArrayList(mPrefMaxSuggestions); Arrays.fill(mScores, 0); // Treating USER_TYPED as UNIGRAM suggestion for logging now. @@ -274,7 +267,7 @@ public class Suggest implements Dictionary.WordCallback { mConsideredWord = ""; Arrays.fill(mBigramScores, 0); - collectGarbage(mBigramSuggestions, PREF_MAX_BIGRAMS); + mBigramSuggestions = new ArrayList(PREF_MAX_BIGRAMS); CharSequence lowerPrevWord = prevWordForBigram.toString().toLowerCase(); if (mMainDict != null && mMainDict.isValidWord(lowerPrevWord)) { @@ -305,7 +298,7 @@ public class Suggest implements Dictionary.WordCallback { mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); mIsAllUpperCase = wordComposer.isAllUpperCase(); mTrailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount(); - collectGarbage(mSuggestions, mPrefMaxSuggestions); + mSuggestions = new ArrayList(mPrefMaxSuggestions); Arrays.fill(mScores, 0); final String typedWord = wordComposer.getTypedWord(); @@ -328,7 +321,7 @@ public class Suggest implements Dictionary.WordCallback { if (wordComposer.size() <= 1 && (correctionMode == CORRECTION_FULL_BIGRAM)) { // At first character typed, search only the bigrams Arrays.fill(mBigramScores, 0); - collectGarbage(mBigramSuggestions, PREF_MAX_BIGRAMS); + mBigramSuggestions = new ArrayList(PREF_MAX_BIGRAMS); if (!TextUtils.isEmpty(prevWordForBigram)) { CharSequence lowerPrevWord = prevWordForBigram.toString().toLowerCase(); @@ -542,7 +535,7 @@ public class Suggest implements Dictionary.WordCallback { System.arraycopy(sortedScores, pos, sortedScores, pos + 1, prefMaxSuggestions - pos - 1); sortedScores[pos] = score; - final StringBuilder sb = StringBuilderPool.getStringBuilder(getApproxMaxWordLength()); + final StringBuilder sb = new StringBuilder(getApproxMaxWordLength()); // TODO: Must pay attention to locale when changing case. if (mIsAllUpperCase) { sb.append(new String(word, offset, length).toUpperCase()); @@ -559,10 +552,7 @@ public class Suggest implements Dictionary.WordCallback { } suggestions.add(pos, sb); if (suggestions.size() > prefMaxSuggestions) { - final CharSequence garbage = suggestions.remove(prefMaxSuggestions); - if (garbage instanceof StringBuilder) { - StringBuilderPool.recycle((StringBuilder)garbage); - } + suggestions.remove(prefMaxSuggestions); } else { LatinImeLogger.onAddSuggestedWord(sb.toString(), dicTypeId, dataTypeForLog); } @@ -589,24 +579,6 @@ public class Suggest implements Dictionary.WordCallback { return -1; } - private static void collectGarbage(ArrayList suggestions, - int prefMaxSuggestions) { - int poolSize = StringBuilderPool.getSize(); - int garbageSize = suggestions.size(); - while (poolSize < prefMaxSuggestions && garbageSize > 0) { - final CharSequence garbage = suggestions.get(garbageSize - 1); - if (garbage instanceof StringBuilder) { - StringBuilderPool.recycle((StringBuilder)garbage); - poolSize++; - } - garbageSize--; - } - if (poolSize == prefMaxSuggestions + 1) { - Log.w("Suggest", "String pool got too big: " + poolSize); - } - suggestions.clear(); - } - public void close() { final Set dictionaries = new HashSet(); dictionaries.addAll(mUnigramDictionaries.values()); -- cgit v1.2.3-83-g751a From 3bf57a5624679a20db26df912077a53b9f90ad36 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Tue, 3 Apr 2012 12:50:28 +0900 Subject: Use "No language (QWERTY)" for language agnostic QWERTY keyboard name Bug: 6010147 Change-Id: I401c2e3fcd639c0e1a03e64489a0d792810caa18 --- java/res/values/donottranslate.xml | 8 +- java/res/values/strings.xml | 2 + java/res/xml/method.xml | 2 +- .../inputmethod/keyboard/LatinKeyboardView.java | 8 +- .../com/android/inputmethod/latin/StringUtils.java | 38 ------- .../android/inputmethod/latin/SubtypeLocale.java | 91 ++++++++++++++-- .../android/inputmethod/latin/SubtypeSwitcher.java | 4 - .../spellcheck/AndroidSpellCheckerService.java | 5 +- .../inputmethod/latin/SubtypeLocaleTests.java | 120 ++++++++++++++++----- 9 files changed, 188 insertions(+), 90 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/StringUtils.java') diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml index 68a8cabce..9c8bd3cd4 100644 --- a/java/res/values/donottranslate.xml +++ b/java/res/values/donottranslate.xml @@ -156,22 +156,20 @@ en_US en_GB - de_QY - zz_QY + *_QY + QY English (US) English (UK) @string/subtype_generic_qwerty - @string/subtype_qwerty + QWERTY %s %s (QWERTY) - - QWERTY com.google.android.inputmethod.latin.dictionarypack diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 4f038e1a5..a22c68cb8 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -252,6 +252,8 @@ English (UK) English (US) + + No language (QWERTY) Usability study mode diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml index 7a21a856b..e43fb32a4 100644 --- a/java/res/xml/method.xml +++ b/java/res/xml/method.xml @@ -312,7 +312,7 @@ android:imeSubtypeExtraValue="AsciiCapable" /> = 0) { - final String languageName = locale.getDisplayLanguage(locale); - return String.format(value, languageName); - } - return value; + if (sExceptionKeys[index].equals(key)) { + return sExceptionValues[index]; } } - return locale.getDisplayName(locale); + return null; + } + + // Get Locale's full display name in its locale. + // For example: + // "fr_CH" is converted to "Français (Suisse)". + // "de_QY" is converted to "Deutsche (QWERTY)". (Any locale that has country code "QY") + // "zz_QY" is converted to "QWERTY". (The language code "zz" means "No language", thus just + // ends up with the keyboard layout name.) + public static String getFullDisplayName(Locale locale) { + final String key; + if (locale.getLanguage().equals(NO_LANGUAGE)) { + key = locale.getCountry(); + } else if (locale.getCountry().equals(QWERTY)) { + key = "*_" + QWERTY; + } else { + key = locale.toString(); + } + final String value = lookupExceptionalLocale(key); + if (value == null) { + return toTitleCase(locale.getDisplayName(locale), locale); + } + if (value.indexOf("%s") >= 0) { + final String languageName = toTitleCase(locale.getDisplayLanguage(locale), locale); + return String.format(value, languageName); + } + return value; + } + + // Get Locale's middle display name in its locale. + // For example: + // "fr_CH" is converted to "Français". + // "de_QY" is converted to "Deutsche". (Any locale that has country code "QY") + // "zz_QY" is converted to "QWERTY". (The language code "zz" means "No language", thus just + // ends up with the keyboard layout name.) + public static String getMiddleDisplayName(Locale locale) { + if (NO_LANGUAGE.equals(locale.getLanguage())) { + return lookupExceptionalLocale(locale.getCountry()); + } else { + return toTitleCase(locale.getDisplayLanguage(locale), locale); + } + } + + // Get Locale's short display name in its locale. + // For example: + // "fr_CH" is converted to "Fr". + // "de_QY" is converted to "De". (Any locale that has country code "QY") + // "zz_QY" is converter to "QY". (The language code "zz" means "No language", thus just ends + // up with the keyboard layout name.) + public static String getShortDisplayName(Locale locale) { + if (NO_LANGUAGE.equals(locale.getLanguage())) { + return locale.getCountry(); + } else { + return toTitleCase(locale.getLanguage(), locale); + } + } + + public static String toTitleCase(String s, Locale locale) { + if (s.length() <= 1) { + // TODO: is this really correct? Shouldn't this be s.toUpperCase()? + return s; + } + // TODO: fix the bugs below + // - This does not work for Greek, because it returns upper case instead of title case. + // - It does not work for Serbian, because it fails to account for the "lj" character, + // which should be "Lj" in title case and "LJ" in upper case. + // - It does not work for Dutch, because it fails to account for the "ij" digraph, which + // are two different characters but both should be capitalized as "IJ" as if they were + // a single letter. + // - It also does not work with unicode surrogate code points. + return s.toUpperCase(locale).charAt(0) + s.substring(1); } } diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index e35364420..c2dafcf73 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -420,10 +420,6 @@ public class SubtypeSwitcher { return KEYBOARD_MODE.equals(getCurrentSubtypeMode()); } - public String getInputLanguageName() { - return StringUtils.getDisplayLanguage(getInputLocale()); - } - ///////////////////////////// // Other utility functions // ///////////////////////////// diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 7b13e40c2..cd01bb146 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -37,6 +37,7 @@ import com.android.inputmethod.latin.Flag; import com.android.inputmethod.latin.LocaleUtils; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StringUtils; +import com.android.inputmethod.latin.SubtypeLocale; import com.android.inputmethod.latin.SynchronouslyLoadedContactsDictionary; import com.android.inputmethod.latin.SynchronouslyLoadedUserDictionary; import com.android.inputmethod.latin.WhitelistDictionary; @@ -325,8 +326,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService } else if (CAPITALIZE_FIRST == capitalizeType) { for (int i = 0; i < mSuggestions.size(); ++i) { // Likewise - mSuggestions.set(i, StringUtils.toTitleCase(mSuggestions.get(i).toString(), - locale)); + mSuggestions.set(i, SubtypeLocale.toTitleCase( + mSuggestions.get(i).toString(), locale)); } } // This returns a String[], while toArray() returns an Object[] which cannot be cast diff --git a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java index 089fdc52c..6180ff5f9 100644 --- a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java +++ b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java @@ -23,11 +23,14 @@ import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; import java.util.ArrayList; -import java.util.List; import java.util.Locale; public class SubtypeLocaleTests extends AndroidTestCase { - private List mKeyboardSubtypes; + private static final Locale LOCALE_zz_QY = SubtypeLocale.LOCALE_NO_LANGUAGE_QWERTY; + private static final Locale LOCALE_de_QY = + new Locale(Locale.GERMAN.getLanguage(), SubtypeLocale.QWERTY); + + private ArrayList mSubtypesList; @Override protected void setUp() throws Exception { @@ -42,46 +45,111 @@ public class SubtypeLocaleTests extends AndroidTestCase { Context.INPUT_METHOD_SERVICE); for (final InputMethodInfo imi : imm.getInputMethodList()) { if (imi.getPackageName().equals(packageName)) { - mKeyboardSubtypes = new ArrayList(); + mSubtypesList = new ArrayList(); final int subtypeCount = imi.getSubtypeCount(); - for (int i = 0; i < subtypeCount; ++i) { - InputMethodSubtype subtype = imi.getSubtypeAt(i); - if (subtype.getMode().equals("keyboard")) { - mKeyboardSubtypes.add(subtype); - } + for (int i = 0; i < subtypeCount; i++) { + final InputMethodSubtype ims = imi.getSubtypeAt(i); + mSubtypesList.add(ims); } break; } } - assertNotNull("Can not find input method " + packageName, mKeyboardSubtypes); - assertTrue("Can not find keyboard subtype", mKeyboardSubtypes.size() > 0); + assertNotNull("Can not find input method " + packageName, mSubtypesList); + assertTrue("Can not find keyboard subtype", mSubtypesList.size() > 0); + } + + private static Locale getSubtypeLocale(InputMethodSubtype subtype) { + return LocaleUtils.constructLocaleFromString(subtype.getLocale()); + } + + private static Locale getKeyboardLocale(InputMethodSubtype subtype) { + final String subtypeLocaleString = subtype.containsExtraValueKey( + LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE) + ? subtype.getExtraValueOf(LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE) + : subtype.getLocale(); + return LocaleUtils.constructLocaleFromString(subtypeLocaleString); } - public void testSubtypeLocale() { + public void testFullDisplayName() { final StringBuilder messages = new StringBuilder(); int failedCount = 0; - for (final InputMethodSubtype subtype : mKeyboardSubtypes) { - final Locale locale = LocaleUtils.constructLocaleFromString(subtype.getLocale()); - if (locale.getLanguage().equals("zz")) { + for (final InputMethodSubtype subtype : mSubtypesList) { + final Locale locale = getKeyboardLocale(subtype); + if (locale.getLanguage().equals(SubtypeLocale.NO_LANGUAGE)) { // This is special language name for language agnostic usage. continue; } - final String subtypeLocaleString = - subtype.containsExtraValueKey(LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE) - ? subtype.getExtraValueOf(LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE) - : subtype.getLocale(); - final Locale subtypeLocale = LocaleUtils.constructLocaleFromString(subtypeLocaleString); - // The subtype name in its locale. For example 'English (US)' or 'Deutsch (QWERTY)'. - final String subtypeName = SubtypeLocale.getFullDisplayName(subtypeLocale); - // The locale language name in its locale. - final String languageName = locale.getDisplayLanguage(locale); - if (!subtypeName.contains(languageName)) { + final String keyboardName = SubtypeLocale.getFullDisplayName(locale); + final String languageName = SubtypeLocale.toTitleCase( + locale.getDisplayLanguage(locale), locale); + if (!keyboardName.contains(languageName)) { failedCount++; messages.append(String.format( - "subtype name is '%s' and should contain locale '%s' language name '%s'\n", - subtypeName, subtypeLocale, languageName)); + "locale %s: keyboard name '%s' should contain language name '%s'\n", + locale, keyboardName, languageName)); } } assertEquals(messages.toString(), 0, failedCount); } + + public void testFullDisplayNameNoLanguage() { + assertEquals("zz_QY", "QWERTY", SubtypeLocale.getFullDisplayName(LOCALE_zz_QY)); + + final String de_QY = SubtypeLocale.getFullDisplayName(LOCALE_de_QY); + assertTrue("de_QY", de_QY.contains("(QWERTY")); + assertTrue("de_QY", de_QY.contains(Locale.GERMAN.getDisplayLanguage(Locale.GERMAN))); + } + + public void testMiddleDisplayName() { + final StringBuilder messages = new StringBuilder(); + int failedCount = 0; + for (final InputMethodSubtype subtype : mSubtypesList) { + final Locale locale = getKeyboardLocale(subtype); + if (locale.getLanguage().equals(SubtypeLocale.NO_LANGUAGE)) { + // This is special language name for language agnostic usage. + continue; + } + final String keyboardName = SubtypeLocale.getMiddleDisplayName(locale); + final String languageName = SubtypeLocale.toTitleCase( + locale.getDisplayLanguage(locale), locale); + if (!keyboardName.equals(languageName)) { + failedCount++; + messages.append(String.format( + "locale %s: keyboard name '%s' should be equals to language name '%s'\n", + locale, keyboardName, languageName)); + } + } + assertEquals(messages.toString(), 0, failedCount); + } + + public void testMiddleDisplayNameNoLanguage() { + assertEquals("zz_QY", "QWERTY", SubtypeLocale.getMiddleDisplayName(LOCALE_zz_QY)); + assertEquals("de_QY", "Deutsch", SubtypeLocale.getMiddleDisplayName(LOCALE_de_QY)); + } + + public void testShortDisplayName() { + final StringBuilder messages = new StringBuilder(); + int failedCount = 0; + for (final InputMethodSubtype subtype : mSubtypesList) { + final Locale locale = getKeyboardLocale(subtype); + if (locale.getCountry().equals(SubtypeLocale.QWERTY)) { + // This is special country code for QWERTY keyboard. + continue; + } + final String keyboardName = SubtypeLocale.getShortDisplayName(locale); + final String languageCode = SubtypeLocale.toTitleCase(locale.getLanguage(), locale); + if (!keyboardName.equals(languageCode)) { + failedCount++; + messages.append(String.format( + "locale %s: keyboard name '%s' should be equals to language code '%s'\n", + locale, keyboardName, languageCode)); + } + } + assertEquals(messages.toString(), 0, failedCount); + } + + public void testShortDisplayNameNoLanguage() { + assertEquals("zz_QY", "QY", SubtypeLocale.getShortDisplayName(LOCALE_zz_QY)); + assertEquals("de_QY", "De", SubtypeLocale.getShortDisplayName(LOCALE_de_QY)); + } } -- cgit v1.2.3-83-g751a From 11d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Wed, 4 Apr 2012 14:30:42 +0900 Subject: Use keyboardSet extra value of subtype to specify layout type Change-Id: Ice1f345a08a8d760e3b847c885c4072e3e142c97 --- java/proguard.flags | 2 +- java/res/values/attrs.xml | 6 +- java/res/xml-ar/keyboard_set.xml | 42 -- java/res/xml-be/keyboard_set.xml | 42 -- java/res/xml-bg/keyboard_set.xml | 42 -- java/res/xml-cs/keyboard_set.xml | 42 -- java/res/xml-da/keyboard_set.xml | 42 -- java/res/xml-de-rQY/keyboard_set.xml | 42 -- java/res/xml-de/keyboard_set.xml | 42 -- java/res/xml-el/keyboard_set.xml | 42 -- java/res/xml-es/keyboard_set.xml | 42 -- java/res/xml-et/keyboard_set.xml | 42 -- java/res/xml-fa/keyboard_set.xml | 42 -- java/res/xml-fi/keyboard_set.xml | 42 -- java/res/xml-fr-rCA/keyboard_set.xml | 42 -- java/res/xml-fr-rCH/keyboard_set.xml | 42 -- java/res/xml-fr/keyboard_set.xml | 42 -- java/res/xml-hi/keyboard_set.xml | 58 --- java/res/xml-hr/keyboard_set.xml | 42 -- java/res/xml-hu/keyboard_set.xml | 42 -- java/res/xml-is/keyboard_set.xml | 42 -- java/res/xml-iw/keyboard_set.xml | 42 -- java/res/xml-ka/keyboard_set.xml | 58 --- java/res/xml-ky/keyboard_set.xml | 42 -- java/res/xml-mk/keyboard_set.xml | 42 -- java/res/xml-nb/keyboard_set.xml | 42 -- java/res/xml-pl/keyboard_set.xml | 42 -- java/res/xml-pt/keyboard_set.xml | 42 -- java/res/xml-ro/keyboard_set.xml | 42 -- java/res/xml-ru/keyboard_set.xml | 42 -- java/res/xml-sk/keyboard_set.xml | 42 -- java/res/xml-sl/keyboard_set.xml | 42 -- java/res/xml-sr/keyboard_set.xml | 42 -- java/res/xml-sv/keyboard_set.xml | 42 -- java/res/xml-sw600dp/key_styles_common.xml | 8 +- java/res/xml-sw600dp/rowkeys_thai1.xml | 2 +- java/res/xml-sw600dp/rowkeys_thai2.xml | 2 +- java/res/xml-sw600dp/rowkeys_thai3.xml | 2 +- java/res/xml-sw600dp/rowkeys_thai4.xml | 2 +- java/res/xml-sw768dp/key_styles_common.xml | 8 +- java/res/xml-th/keyboard_set.xml | 58 --- java/res/xml-tr/keyboard_set.xml | 42 -- java/res/xml-uk/keyboard_set.xml | 42 -- java/res/xml-vi/keyboard_set.xml | 42 -- java/res/xml-zz-rQY/keyboard_set.xml | 42 -- java/res/xml/key_azerty_quote.xml | 2 +- java/res/xml/key_greek_semicolon.xml | 2 +- java/res/xml/key_styles_common.xml | 6 +- java/res/xml/key_styles_enter.xml | 2 +- java/res/xml/keyboard_layout_set_arabic.xml | 42 ++ java/res/xml/keyboard_layout_set_azerty.xml | 42 ++ java/res/xml/keyboard_layout_set_bulgarian.xml | 42 ++ java/res/xml/keyboard_layout_set_east_slavic.xml | 42 ++ java/res/xml/keyboard_layout_set_farsi.xml | 42 ++ java/res/xml/keyboard_layout_set_georgian.xml | 58 +++ java/res/xml/keyboard_layout_set_greek.xml | 42 ++ java/res/xml/keyboard_layout_set_hebrew.xml | 42 ++ java/res/xml/keyboard_layout_set_hindi.xml | 58 +++ java/res/xml/keyboard_layout_set_nordic.xml | 42 ++ java/res/xml/keyboard_layout_set_qwerty.xml | 42 ++ java/res/xml/keyboard_layout_set_qwertz.xml | 42 ++ java/res/xml/keyboard_layout_set_south_slavic.xml | 42 ++ java/res/xml/keyboard_layout_set_spanish.xml | 42 ++ java/res/xml/keyboard_layout_set_thai.xml | 58 +++ java/res/xml/keyboard_set.xml | 42 -- java/res/xml/method.xml | 80 ++-- java/res/xml/rowkeys_georgian1.xml | 2 +- java/res/xml/rowkeys_georgian2.xml | 2 +- java/res/xml/rowkeys_georgian3.xml | 2 +- java/res/xml/rowkeys_greek1.xml | 2 +- java/res/xml/rowkeys_hindi1.xml | 2 +- java/res/xml/rowkeys_hindi2.xml | 2 +- java/res/xml/rowkeys_hindi3.xml | 2 +- java/res/xml/rowkeys_thai1.xml | 2 +- java/res/xml/rowkeys_thai2.xml | 2 +- java/res/xml/rowkeys_thai3.xml | 2 +- .../com/android/inputmethod/keyboard/Keyboard.java | 15 +- .../inputmethod/keyboard/KeyboardLayoutSet.java | 447 +++++++++++++++++++++ .../android/inputmethod/keyboard/KeyboardSet.java | 407 ------------------- .../inputmethod/keyboard/KeyboardSwitcher.java | 27 +- .../keyboard/internal/KeySpecParser.java | 2 +- .../com/android/inputmethod/latin/LatinIME.java | 11 +- .../com/android/inputmethod/latin/StringUtils.java | 17 + .../android/inputmethod/latin/SubtypeLocale.java | 36 +- .../android/inputmethod/latin/SubtypeSwitcher.java | 27 +- .../android/inputmethod/latin/SubtypeUtils.java | 16 + .../spellcheck/AndroidSpellCheckerService.java | 3 +- .../inputmethod/latin/SubtypeLocaleTests.java | 26 +- 88 files changed, 1295 insertions(+), 2205 deletions(-) delete mode 100644 java/res/xml-ar/keyboard_set.xml delete mode 100644 java/res/xml-be/keyboard_set.xml delete mode 100644 java/res/xml-bg/keyboard_set.xml delete mode 100644 java/res/xml-cs/keyboard_set.xml delete mode 100644 java/res/xml-da/keyboard_set.xml delete mode 100644 java/res/xml-de-rQY/keyboard_set.xml delete mode 100644 java/res/xml-de/keyboard_set.xml delete mode 100644 java/res/xml-el/keyboard_set.xml delete mode 100644 java/res/xml-es/keyboard_set.xml delete mode 100644 java/res/xml-et/keyboard_set.xml delete mode 100644 java/res/xml-fa/keyboard_set.xml delete mode 100644 java/res/xml-fi/keyboard_set.xml delete mode 100644 java/res/xml-fr-rCA/keyboard_set.xml delete mode 100644 java/res/xml-fr-rCH/keyboard_set.xml delete mode 100644 java/res/xml-fr/keyboard_set.xml delete mode 100644 java/res/xml-hi/keyboard_set.xml delete mode 100644 java/res/xml-hr/keyboard_set.xml delete mode 100644 java/res/xml-hu/keyboard_set.xml delete mode 100644 java/res/xml-is/keyboard_set.xml delete mode 100644 java/res/xml-iw/keyboard_set.xml delete mode 100644 java/res/xml-ka/keyboard_set.xml delete mode 100644 java/res/xml-ky/keyboard_set.xml delete mode 100644 java/res/xml-mk/keyboard_set.xml delete mode 100644 java/res/xml-nb/keyboard_set.xml delete mode 100644 java/res/xml-pl/keyboard_set.xml delete mode 100644 java/res/xml-pt/keyboard_set.xml delete mode 100644 java/res/xml-ro/keyboard_set.xml delete mode 100644 java/res/xml-ru/keyboard_set.xml delete mode 100644 java/res/xml-sk/keyboard_set.xml delete mode 100644 java/res/xml-sl/keyboard_set.xml delete mode 100644 java/res/xml-sr/keyboard_set.xml delete mode 100644 java/res/xml-sv/keyboard_set.xml delete mode 100644 java/res/xml-th/keyboard_set.xml delete mode 100644 java/res/xml-tr/keyboard_set.xml delete mode 100644 java/res/xml-uk/keyboard_set.xml delete mode 100644 java/res/xml-vi/keyboard_set.xml delete mode 100644 java/res/xml-zz-rQY/keyboard_set.xml create mode 100644 java/res/xml/keyboard_layout_set_arabic.xml create mode 100644 java/res/xml/keyboard_layout_set_azerty.xml create mode 100644 java/res/xml/keyboard_layout_set_bulgarian.xml create mode 100644 java/res/xml/keyboard_layout_set_east_slavic.xml create mode 100644 java/res/xml/keyboard_layout_set_farsi.xml create mode 100644 java/res/xml/keyboard_layout_set_georgian.xml create mode 100644 java/res/xml/keyboard_layout_set_greek.xml create mode 100644 java/res/xml/keyboard_layout_set_hebrew.xml create mode 100644 java/res/xml/keyboard_layout_set_hindi.xml create mode 100644 java/res/xml/keyboard_layout_set_nordic.xml create mode 100644 java/res/xml/keyboard_layout_set_qwerty.xml create mode 100644 java/res/xml/keyboard_layout_set_qwertz.xml create mode 100644 java/res/xml/keyboard_layout_set_south_slavic.xml create mode 100644 java/res/xml/keyboard_layout_set_spanish.xml create mode 100644 java/res/xml/keyboard_layout_set_thai.xml delete mode 100644 java/res/xml/keyboard_set.xml create mode 100644 java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java delete mode 100644 java/src/com/android/inputmethod/keyboard/KeyboardSet.java (limited to 'java/src/com/android/inputmethod/latin/StringUtils.java') diff --git a/java/proguard.flags b/java/proguard.flags index 2ee1a263f..44f8581cc 100644 --- a/java/proguard.flags +++ b/java/proguard.flags @@ -40,7 +40,7 @@ void setLogFileManager(...); } --keep class com.android.inputmethod.keyboard.KeyboardSet$Builder { +-keep class com.android.inputmethod.keyboard.KeyboardLayoutSet$Builder { void setTouchPositionCorrectionEnabled(...); } diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index 86f2abe72..39d50e348 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -350,8 +350,8 @@ - - + + @@ -403,7 +403,7 @@ - + diff --git a/java/res/xml-ar/keyboard_set.xml b/java/res/xml-ar/keyboard_set.xml deleted file mode 100644 index 88d320144..000000000 --- a/java/res/xml-ar/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-be/keyboard_set.xml b/java/res/xml-be/keyboard_set.xml deleted file mode 100644 index 959f644ea..000000000 --- a/java/res/xml-be/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-bg/keyboard_set.xml b/java/res/xml-bg/keyboard_set.xml deleted file mode 100644 index 593ad977c..000000000 --- a/java/res/xml-bg/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-cs/keyboard_set.xml b/java/res/xml-cs/keyboard_set.xml deleted file mode 100644 index f9f74516f..000000000 --- a/java/res/xml-cs/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-da/keyboard_set.xml b/java/res/xml-da/keyboard_set.xml deleted file mode 100644 index 0db9b1f59..000000000 --- a/java/res/xml-da/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-de-rQY/keyboard_set.xml b/java/res/xml-de-rQY/keyboard_set.xml deleted file mode 100644 index 8966ddbb0..000000000 --- a/java/res/xml-de-rQY/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-de/keyboard_set.xml b/java/res/xml-de/keyboard_set.xml deleted file mode 100644 index f9f74516f..000000000 --- a/java/res/xml-de/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-el/keyboard_set.xml b/java/res/xml-el/keyboard_set.xml deleted file mode 100644 index af74e12c5..000000000 --- a/java/res/xml-el/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-es/keyboard_set.xml b/java/res/xml-es/keyboard_set.xml deleted file mode 100644 index 4ff5b54f2..000000000 --- a/java/res/xml-es/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-et/keyboard_set.xml b/java/res/xml-et/keyboard_set.xml deleted file mode 100644 index 0db9b1f59..000000000 --- a/java/res/xml-et/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-fa/keyboard_set.xml b/java/res/xml-fa/keyboard_set.xml deleted file mode 100644 index f508f8f29..000000000 --- a/java/res/xml-fa/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-fi/keyboard_set.xml b/java/res/xml-fi/keyboard_set.xml deleted file mode 100644 index 0db9b1f59..000000000 --- a/java/res/xml-fi/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-fr-rCA/keyboard_set.xml b/java/res/xml-fr-rCA/keyboard_set.xml deleted file mode 100644 index 8966ddbb0..000000000 --- a/java/res/xml-fr-rCA/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-fr-rCH/keyboard_set.xml b/java/res/xml-fr-rCH/keyboard_set.xml deleted file mode 100644 index f9f74516f..000000000 --- a/java/res/xml-fr-rCH/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-fr/keyboard_set.xml b/java/res/xml-fr/keyboard_set.xml deleted file mode 100644 index 2ac25c91d..000000000 --- a/java/res/xml-fr/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-hi/keyboard_set.xml b/java/res/xml-hi/keyboard_set.xml deleted file mode 100644 index c1fd0712d..000000000 --- a/java/res/xml-hi/keyboard_set.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/java/res/xml-hr/keyboard_set.xml b/java/res/xml-hr/keyboard_set.xml deleted file mode 100644 index f9f74516f..000000000 --- a/java/res/xml-hr/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-hu/keyboard_set.xml b/java/res/xml-hu/keyboard_set.xml deleted file mode 100644 index f9f74516f..000000000 --- a/java/res/xml-hu/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-is/keyboard_set.xml b/java/res/xml-is/keyboard_set.xml deleted file mode 100644 index 44edbba3e..000000000 --- a/java/res/xml-is/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-iw/keyboard_set.xml b/java/res/xml-iw/keyboard_set.xml deleted file mode 100644 index 6c51fb085..000000000 --- a/java/res/xml-iw/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-ka/keyboard_set.xml b/java/res/xml-ka/keyboard_set.xml deleted file mode 100644 index bc3df1ed0..000000000 --- a/java/res/xml-ka/keyboard_set.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/java/res/xml-ky/keyboard_set.xml b/java/res/xml-ky/keyboard_set.xml deleted file mode 100644 index 959f644ea..000000000 --- a/java/res/xml-ky/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-mk/keyboard_set.xml b/java/res/xml-mk/keyboard_set.xml deleted file mode 100644 index 6b8b84434..000000000 --- a/java/res/xml-mk/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-nb/keyboard_set.xml b/java/res/xml-nb/keyboard_set.xml deleted file mode 100644 index 0db9b1f59..000000000 --- a/java/res/xml-nb/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-pl/keyboard_set.xml b/java/res/xml-pl/keyboard_set.xml deleted file mode 100644 index 8966ddbb0..000000000 --- a/java/res/xml-pl/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-pt/keyboard_set.xml b/java/res/xml-pt/keyboard_set.xml deleted file mode 100644 index 8966ddbb0..000000000 --- a/java/res/xml-pt/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-ro/keyboard_set.xml b/java/res/xml-ro/keyboard_set.xml deleted file mode 100644 index 8966ddbb0..000000000 --- a/java/res/xml-ro/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-ru/keyboard_set.xml b/java/res/xml-ru/keyboard_set.xml deleted file mode 100644 index 959f644ea..000000000 --- a/java/res/xml-ru/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-sk/keyboard_set.xml b/java/res/xml-sk/keyboard_set.xml deleted file mode 100644 index 8966ddbb0..000000000 --- a/java/res/xml-sk/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-sl/keyboard_set.xml b/java/res/xml-sl/keyboard_set.xml deleted file mode 100644 index 8966ddbb0..000000000 --- a/java/res/xml-sl/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-sr/keyboard_set.xml b/java/res/xml-sr/keyboard_set.xml deleted file mode 100644 index 5098134a7..000000000 --- a/java/res/xml-sr/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-sv/keyboard_set.xml b/java/res/xml-sv/keyboard_set.xml deleted file mode 100644 index 0db9b1f59..000000000 --- a/java/res/xml-sv/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-sw600dp/key_styles_common.xml b/java/res/xml-sw600dp/key_styles_common.xml index 77c0efd22..45e22fce3 100644 --- a/java/res/xml-sw600dp/key_styles_common.xml +++ b/java/res/xml-sw600dp/key_styles_common.xml @@ -23,7 +23,7 @@ > diff --git a/java/res/xml-sw768dp/key_styles_common.xml b/java/res/xml-sw768dp/key_styles_common.xml index f4a1a4ea5..e1c236912 100644 --- a/java/res/xml-sw768dp/key_styles_common.xml +++ b/java/res/xml-sw768dp/key_styles_common.xml @@ -23,7 +23,7 @@ > - - - - - - - - - - - - - - - diff --git a/java/res/xml-tr/keyboard_set.xml b/java/res/xml-tr/keyboard_set.xml deleted file mode 100644 index 8966ddbb0..000000000 --- a/java/res/xml-tr/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-uk/keyboard_set.xml b/java/res/xml-uk/keyboard_set.xml deleted file mode 100644 index 959f644ea..000000000 --- a/java/res/xml-uk/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-vi/keyboard_set.xml b/java/res/xml-vi/keyboard_set.xml deleted file mode 100644 index 8966ddbb0..000000000 --- a/java/res/xml-vi/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-zz-rQY/keyboard_set.xml b/java/res/xml-zz-rQY/keyboard_set.xml deleted file mode 100644 index e9eddbf05..000000000 --- a/java/res/xml-zz-rQY/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml/key_azerty_quote.xml b/java/res/xml/key_azerty_quote.xml index 8c44f7862..966ae6f21 100644 --- a/java/res/xml/key_azerty_quote.xml +++ b/java/res/xml/key_azerty_quote.xml @@ -23,7 +23,7 @@ > diff --git a/java/res/xml/key_greek_semicolon.xml b/java/res/xml/key_greek_semicolon.xml index a28b772fd..ae73a59f6 100644 --- a/java/res/xml/key_greek_semicolon.xml +++ b/java/res/xml/key_greek_semicolon.xml @@ -23,7 +23,7 @@ > + + + + + + + + + + diff --git a/java/res/xml/keyboard_layout_set_azerty.xml b/java/res/xml/keyboard_layout_set_azerty.xml new file mode 100644 index 000000000..d4df6676c --- /dev/null +++ b/java/res/xml/keyboard_layout_set_azerty.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + diff --git a/java/res/xml/keyboard_layout_set_bulgarian.xml b/java/res/xml/keyboard_layout_set_bulgarian.xml new file mode 100644 index 000000000..c6fdff9a2 --- /dev/null +++ b/java/res/xml/keyboard_layout_set_bulgarian.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + diff --git a/java/res/xml/keyboard_layout_set_east_slavic.xml b/java/res/xml/keyboard_layout_set_east_slavic.xml new file mode 100644 index 000000000..8d66faf8f --- /dev/null +++ b/java/res/xml/keyboard_layout_set_east_slavic.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + diff --git a/java/res/xml/keyboard_layout_set_farsi.xml b/java/res/xml/keyboard_layout_set_farsi.xml new file mode 100644 index 000000000..b9a91e3a8 --- /dev/null +++ b/java/res/xml/keyboard_layout_set_farsi.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + diff --git a/java/res/xml/keyboard_layout_set_georgian.xml b/java/res/xml/keyboard_layout_set_georgian.xml new file mode 100644 index 000000000..36d091653 --- /dev/null +++ b/java/res/xml/keyboard_layout_set_georgian.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + diff --git a/java/res/xml/keyboard_layout_set_greek.xml b/java/res/xml/keyboard_layout_set_greek.xml new file mode 100644 index 000000000..b376e4fe3 --- /dev/null +++ b/java/res/xml/keyboard_layout_set_greek.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + diff --git a/java/res/xml/keyboard_layout_set_hebrew.xml b/java/res/xml/keyboard_layout_set_hebrew.xml new file mode 100644 index 000000000..d0f12f3ee --- /dev/null +++ b/java/res/xml/keyboard_layout_set_hebrew.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + diff --git a/java/res/xml/keyboard_layout_set_hindi.xml b/java/res/xml/keyboard_layout_set_hindi.xml new file mode 100644 index 000000000..e850c7ebc --- /dev/null +++ b/java/res/xml/keyboard_layout_set_hindi.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + diff --git a/java/res/xml/keyboard_layout_set_nordic.xml b/java/res/xml/keyboard_layout_set_nordic.xml new file mode 100644 index 000000000..1f00f440e --- /dev/null +++ b/java/res/xml/keyboard_layout_set_nordic.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + diff --git a/java/res/xml/keyboard_layout_set_qwerty.xml b/java/res/xml/keyboard_layout_set_qwerty.xml new file mode 100644 index 000000000..821517081 --- /dev/null +++ b/java/res/xml/keyboard_layout_set_qwerty.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + diff --git a/java/res/xml/keyboard_layout_set_qwertz.xml b/java/res/xml/keyboard_layout_set_qwertz.xml new file mode 100644 index 000000000..f9e87a66f --- /dev/null +++ b/java/res/xml/keyboard_layout_set_qwertz.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + diff --git a/java/res/xml/keyboard_layout_set_south_slavic.xml b/java/res/xml/keyboard_layout_set_south_slavic.xml new file mode 100644 index 000000000..36666b91b --- /dev/null +++ b/java/res/xml/keyboard_layout_set_south_slavic.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + diff --git a/java/res/xml/keyboard_layout_set_spanish.xml b/java/res/xml/keyboard_layout_set_spanish.xml new file mode 100644 index 000000000..0ef712b76 --- /dev/null +++ b/java/res/xml/keyboard_layout_set_spanish.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + diff --git a/java/res/xml/keyboard_layout_set_thai.xml b/java/res/xml/keyboard_layout_set_thai.xml new file mode 100644 index 000000000..94713e3d4 --- /dev/null +++ b/java/res/xml/keyboard_layout_set_thai.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + diff --git a/java/res/xml/keyboard_set.xml b/java/res/xml/keyboard_set.xml deleted file mode 100644 index 8966ddbb0..000000000 --- a/java/res/xml/keyboard_set.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml index e43fb32a4..ba4534351 100644 --- a/java/res/xml/method.xml +++ b/java/res/xml/method.xml @@ -20,7 +20,8 @@ - diff --git a/java/res/xml/rowkeys_georgian1.xml b/java/res/xml/rowkeys_georgian1.xml index 6b24c29fe..fcdf3fa58 100644 --- a/java/res/xml/rowkeys_georgian1.xml +++ b/java/res/xml/rowkeys_georgian1.xml @@ -23,7 +23,7 @@ > U+0385: "΅" GREEK DIALYTIKA TONOS diff --git a/java/res/xml/rowkeys_hindi2.xml b/java/res/xml/rowkeys_hindi2.xml index 95f488102..05e3db202 100644 --- a/java/res/xml/rowkeys_hindi2.xml +++ b/java/res/xml/rowkeys_hindi2.xml @@ -23,7 +23,7 @@ > mAltCodeKeysWhileTyping = new ArrayList(); public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); - public KeyboardSet.KeysCache mKeysCache; + public KeyboardLayoutSet.KeysCache mKeysCache; public int mMostCommonKeyHeight = 0; public int mMostCommonKeyWidth = 0; @@ -637,7 +637,7 @@ public class Keyboard { params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height); } - public void setAutoGenerate(KeyboardSet.KeysCache keysCache) { + public void setAutoGenerate(KeyboardLayoutSet.KeysCache keysCache) { mParams.mKeysCache = keysCache; } @@ -1061,8 +1061,8 @@ public class Keyboard { final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard_Case); try { - final boolean keyboardSetElementMatched = matchTypedValue(a, - R.styleable.Keyboard_Case_keyboardSetElement, id.mElementId, + final boolean keyboardLayoutSetElementMatched = matchTypedValue(a, + R.styleable.Keyboard_Case_keyboardLayoutSetElement, id.mElementId, KeyboardId.elementIdToName(id.mElementId)); final boolean modeMatched = matchTypedValue(a, R.styleable.Keyboard_Case_mode, id.mMode, KeyboardId.modeName(id.mMode)); @@ -1091,7 +1091,7 @@ public class Keyboard { R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage()); final boolean countryCodeMatched = matchString(a, R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry()); - final boolean selected = keyboardSetElementMatched && modeMatched + final boolean selected = keyboardLayoutSetElementMatched && modeMatched && navigateNextMatched && navigatePreviousMatched && passwordInputMatched && clobberSettingsKeyMatched && shortcutKeyEnabledMatched && hasShortcutKeyMatched && languageSwitchKeyEnabledMatched @@ -1100,8 +1100,9 @@ public class Keyboard { if (DEBUG) { startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE, - textAttr(a.getString(R.styleable.Keyboard_Case_keyboardSetElement), - "keyboardSetElement"), + textAttr(a.getString( + R.styleable.Keyboard_Case_keyboardLayoutSetElement), + "keyboardLayoutSetElement"), textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"), textAttr(a.getString(R.styleable.Keyboard_Case_imeAction), "imeAction"), diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java new file mode 100644 index 000000000..51cd90549 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java @@ -0,0 +1,447 @@ +/* + * Copyright (C) 2011 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 com.android.inputmethod.keyboard; + +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.text.InputType; +import android.util.Log; +import android.util.Xml; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodSubtype; + +import com.android.inputmethod.compat.EditorInfoCompatUtils; +import com.android.inputmethod.keyboard.KeyboardLayoutSet.Params.ElementParams; +import com.android.inputmethod.keyboard.internal.KeySpecParser; +import com.android.inputmethod.latin.InputTypeUtils; +import com.android.inputmethod.latin.LatinIME; +import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.LocaleUtils; +import com.android.inputmethod.latin.LocaleUtils.RunInLocale; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.StringUtils; +import com.android.inputmethod.latin.SubtypeLocale; +import com.android.inputmethod.latin.SubtypeSwitcher; +import com.android.inputmethod.latin.XmlParseUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.lang.ref.SoftReference; +import java.util.HashMap; +import java.util.Locale; + +/** + * This class represents a set of keyboard layouts. Each of them represents a different keyboard + * specific to a keyboard state, such as alphabet, symbols, and so on. Layouts in the same + * {@link KeyboardLayoutSet} are related to each other. + * A {@link KeyboardLayoutSet} needs to be created for each + * {@link android.view.inputmethod.EditorInfo}. + */ +public class KeyboardLayoutSet { + private static final String TAG = KeyboardLayoutSet.class.getSimpleName(); + private static final boolean DEBUG_CACHE = LatinImeLogger.sDBG; + + private static final String TAG_KEYBOARD_SET = "KeyboardLayoutSet"; + private static final String TAG_ELEMENT = "Element"; + + private static final String DEFAULT_KEYBOARD_LAYOUT_SET = "qwerty"; + private static final char KEYBOARD_LAYOUT_SET_LOCALE_DELIMITER = ':'; + private static final String KEYBOARD_LAYOUT_SET_RESOURCE_PREFIX = "xml/keyboard_layout_set_"; + private static final int DEFAULT_KEYBOARD_LAYOUT_SET_RESOURCE_ID = + R.xml.keyboard_layout_set_qwerty; + + private final Context mContext; + private final Params mParams; + + private static final HashMap> sKeyboardCache = + new HashMap>(); + private static final KeysCache sKeysCache = new KeysCache(); + + public static class KeyboardLayoutSetException extends RuntimeException { + public final KeyboardId mKeyboardId; + + public KeyboardLayoutSetException(Throwable cause, KeyboardId keyboardId) { + super(cause); + mKeyboardId = keyboardId; + } + } + + public static class KeysCache { + private final HashMap mMap; + + public KeysCache() { + mMap = new HashMap(); + } + + public void clear() { + mMap.clear(); + } + + public Key get(Key key) { + final Key existingKey = mMap.get(key); + if (existingKey != null) { + // Reuse the existing element that equals to "key" without adding "key" to the map. + return existingKey; + } + mMap.put(key, key); + return key; + } + } + + static class Params { + String mKeyboardLayoutSetName; + int mMode; + EditorInfo mEditorInfo; + boolean mTouchPositionCorrectionEnabled; + boolean mVoiceKeyEnabled; + boolean mVoiceKeyOnMain; + boolean mNoSettingsKey; + boolean mLanguageSwitchKeyEnabled; + Locale mLocale; + int mOrientation; + int mWidth; + // KeyboardLayoutSet element id to element's parameters map. + final HashMap mKeyboardLayoutSetElementIdToParamsMap = + new HashMap(); + + static class ElementParams { + int mKeyboardXmlId; + boolean mProximityCharsCorrectionEnabled; + } + } + + public static void clearKeyboardCache() { + sKeyboardCache.clear(); + sKeysCache.clear(); + } + + private KeyboardLayoutSet(Context context, Params params) { + mContext = context; + mParams = params; + } + + public Keyboard getKeyboard(int baseKeyboardLayoutSetElementId) { + final int keyboardLayoutSetElementId; + switch (mParams.mMode) { + case KeyboardId.MODE_PHONE: + if (baseKeyboardLayoutSetElementId == KeyboardId.ELEMENT_SYMBOLS) { + keyboardLayoutSetElementId = KeyboardId.ELEMENT_PHONE_SYMBOLS; + } else { + keyboardLayoutSetElementId = KeyboardId.ELEMENT_PHONE; + } + break; + case KeyboardId.MODE_NUMBER: + case KeyboardId.MODE_DATE: + case KeyboardId.MODE_TIME: + case KeyboardId.MODE_DATETIME: + keyboardLayoutSetElementId = KeyboardId.ELEMENT_NUMBER; + break; + default: + keyboardLayoutSetElementId = baseKeyboardLayoutSetElementId; + break; + } + + ElementParams elementParams = mParams.mKeyboardLayoutSetElementIdToParamsMap.get( + keyboardLayoutSetElementId); + if (elementParams == null) { + elementParams = mParams.mKeyboardLayoutSetElementIdToParamsMap.get( + KeyboardId.ELEMENT_ALPHABET); + } + final KeyboardId id = getKeyboardId(keyboardLayoutSetElementId); + try { + return getKeyboard(mContext, elementParams, id); + } catch (RuntimeException e) { + throw new KeyboardLayoutSetException(e, id); + } + } + + private Keyboard getKeyboard(Context context, ElementParams elementParams, + final KeyboardId id) { + final SoftReference ref = sKeyboardCache.get(id); + Keyboard keyboard = (ref == null) ? null : ref.get(); + if (keyboard == null) { + final Keyboard.Builder builder = + new Keyboard.Builder(mContext, new Keyboard.Params()); + if (id.isAlphabetKeyboard()) { + builder.setAutoGenerate(sKeysCache); + } + final int keyboardXmlId = elementParams.mKeyboardXmlId; + final RunInLocale job = new RunInLocale() { + @Override + protected Void job(Resources res) { + builder.load(keyboardXmlId, id); + return null; + } + }; + job.runInLocale(context.getResources(), id.mLocale); + builder.setTouchPositionCorrectionEnabled(mParams.mTouchPositionCorrectionEnabled); + builder.setProximityCharsCorrectionEnabled( + elementParams.mProximityCharsCorrectionEnabled); + keyboard = builder.build(); + sKeyboardCache.put(id, new SoftReference(keyboard)); + + if (DEBUG_CACHE) { + Log.d(TAG, "keyboard cache size=" + sKeyboardCache.size() + ": " + + ((ref == null) ? "LOAD" : "GCed") + " id=" + id); + } + } else if (DEBUG_CACHE) { + Log.d(TAG, "keyboard cache size=" + sKeyboardCache.size() + ": HIT id=" + id); + } + + return keyboard; + } + + // Note: The keyboard for each locale, shift state, and mode are represented as + // KeyboardLayoutSet element id that is a key in keyboard_set.xml. Also that file specifies + // which XML layout should be used for each keyboard. The KeyboardId is an internal key for + // Keyboard object. + private KeyboardId getKeyboardId(int keyboardLayoutSetElementId) { + final Params params = mParams; + final boolean isSymbols = (keyboardLayoutSetElementId == KeyboardId.ELEMENT_SYMBOLS + || keyboardLayoutSetElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED); + final boolean noLanguage = params.mLocale.getLanguage().equals(SubtypeLocale.NO_LANGUAGE); + final boolean voiceKeyEnabled = params.mVoiceKeyEnabled && !noLanguage; + final boolean hasShortcutKey = voiceKeyEnabled && (isSymbols != params.mVoiceKeyOnMain); + return new KeyboardId(keyboardLayoutSetElementId, params.mLocale, params.mOrientation, + params.mWidth, params.mMode, params.mEditorInfo, params.mNoSettingsKey, + voiceKeyEnabled, hasShortcutKey, params.mLanguageSwitchKeyEnabled); + } + + private static String getKeyboardLayoutSetName(InputMethodSubtype subtype) { + final String keyboardLayoutSet = subtype.getExtraValueOf( + LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET); + // TODO: Remove this null check when InputMethodManager.getCurrentInputMethodSubtype is + // fixed. + if (keyboardLayoutSet == null) return DEFAULT_KEYBOARD_LAYOUT_SET; + final int pos = keyboardLayoutSet.indexOf(KEYBOARD_LAYOUT_SET_LOCALE_DELIMITER); + return (pos > 0) ? keyboardLayoutSet.substring(0, pos) : keyboardLayoutSet; + } + + public static String getKeyboardLayoutSetLocaleString(InputMethodSubtype subtype) { + final String keyboardLayoutSet = subtype.getExtraValueOf( + LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET); + // TODO: Remove this null check when InputMethodManager.getCurrentInputMethodSubtype is + // fixed. + if (keyboardLayoutSet == null) return subtype.getLocale(); + final int pos = keyboardLayoutSet.indexOf(KEYBOARD_LAYOUT_SET_LOCALE_DELIMITER); + return (pos > 0) ? keyboardLayoutSet.substring(pos + 1) : subtype.getLocale(); + } + + public static Locale getKeyboardLayoutSetLocale(InputMethodSubtype subtype) { + return LocaleUtils.constructLocaleFromString(getKeyboardLayoutSetLocaleString(subtype)); + } + + public static class Builder { + private final Context mContext; + private final String mPackageName; + private final Resources mResources; + private final EditorInfo mEditorInfo; + + private final Params mParams = new Params(); + + private static final EditorInfo EMPTY_EDITOR_INFO = new EditorInfo(); + + public Builder(Context context, EditorInfo editorInfo) { + mContext = context; + mPackageName = context.getPackageName(); + mResources = context.getResources(); + mEditorInfo = editorInfo; + final Params params = mParams; + + params.mMode = getKeyboardMode(editorInfo); + params.mEditorInfo = (editorInfo != null) ? editorInfo : EMPTY_EDITOR_INFO; + params.mNoSettingsKey = StringUtils.inPrivateImeOptions( + mPackageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, mEditorInfo); + } + + public Builder setScreenGeometry(int orientation, int widthPixels) { + mParams.mOrientation = orientation; + mParams.mWidth = widthPixels; + return this; + } + + public Builder setSubtype(InputMethodSubtype subtype) { + final boolean asciiCapable = subtype.containsExtraValueKey( + LatinIME.SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE); + final boolean deprecatedForceAscii = StringUtils.inPrivateImeOptions( + mPackageName, LatinIME.IME_OPTION_FORCE_ASCII, mEditorInfo); + final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii( + mParams.mEditorInfo.imeOptions) + || deprecatedForceAscii; + final InputMethodSubtype keyboardSubtype = (forceAscii && !asciiCapable) + ? SubtypeSwitcher.getInstance().getNoLanguageSubtype() + : subtype; + mParams.mLocale = getKeyboardLayoutSetLocale(keyboardSubtype); + mParams.mKeyboardLayoutSetName = KEYBOARD_LAYOUT_SET_RESOURCE_PREFIX + + getKeyboardLayoutSetName(keyboardSubtype); + return this; + } + + public Builder setOptions(boolean voiceKeyEnabled, boolean voiceKeyOnMain, + boolean languageSwitchKeyEnabled) { + @SuppressWarnings("deprecation") + final boolean deprecatedNoMicrophone = StringUtils.inPrivateImeOptions( + null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, mEditorInfo); + final boolean noMicrophone = StringUtils.inPrivateImeOptions( + mPackageName, LatinIME.IME_OPTION_NO_MICROPHONE, mEditorInfo) + || deprecatedNoMicrophone; + mParams.mVoiceKeyEnabled = voiceKeyEnabled && !noMicrophone; + mParams.mVoiceKeyOnMain = voiceKeyOnMain; + mParams.mLanguageSwitchKeyEnabled = languageSwitchKeyEnabled; + return this; + } + + public void setTouchPositionCorrectionEnabled(boolean enabled) { + mParams.mTouchPositionCorrectionEnabled = enabled; + } + + public KeyboardLayoutSet build() { + if (mParams.mOrientation == Configuration.ORIENTATION_UNDEFINED) + throw new RuntimeException("Screen geometry is not specified"); + if (mParams.mLocale == null) + throw new RuntimeException("KeyboardLayoutSet subtype is not specified"); + final String keyboardLayoutSetName = mParams.mKeyboardLayoutSetName; + final int xmlId = KeySpecParser.getResourceId( + mResources, keyboardLayoutSetName, DEFAULT_KEYBOARD_LAYOUT_SET_RESOURCE_ID); + final RunInLocale job = new RunInLocale() { + @Override + protected Void job(Resources res) { + try { + parseKeyboardLayoutSet(res, xmlId); + } catch (Exception e) { + throw new RuntimeException(e.getMessage() + " in " + keyboardLayoutSetName); + } + return null; + } + }; + job.runInLocale(mResources, mParams.mLocale); + return new KeyboardLayoutSet(mContext, mParams); + } + + private void parseKeyboardLayoutSet(Resources res, int resId) + throws XmlPullParserException, IOException { + final XmlResourceParser parser = res.getXml(resId); + try { + int event; + while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + if (event == XmlPullParser.START_TAG) { + final String tag = parser.getName(); + if (TAG_KEYBOARD_SET.equals(tag)) { + parseKeyboardLayoutSetContent(parser); + } else { + throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD_SET); + } + } + } + } finally { + parser.close(); + } + } + + private void parseKeyboardLayoutSetContent(XmlPullParser parser) + throws XmlPullParserException, IOException { + int event; + while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + if (event == XmlPullParser.START_TAG) { + final String tag = parser.getName(); + if (TAG_ELEMENT.equals(tag)) { + parseKeyboardLayoutSetElement(parser); + } else { + throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD_SET); + } + } else if (event == XmlPullParser.END_TAG) { + final String tag = parser.getName(); + if (TAG_KEYBOARD_SET.equals(tag)) { + break; + } else { + throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEYBOARD_SET); + } + } + } + } + + private void parseKeyboardLayoutSetElement(XmlPullParser parser) + throws XmlPullParserException, IOException { + final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.KeyboardLayoutSet_Element); + try { + XmlParseUtils.checkAttributeExists(a, + R.styleable.KeyboardLayoutSet_Element_elementName, "elementName", + TAG_ELEMENT, parser); + XmlParseUtils.checkAttributeExists(a, + R.styleable.KeyboardLayoutSet_Element_elementKeyboard, "elementKeyboard", + TAG_ELEMENT, parser); + XmlParseUtils.checkEndTag(TAG_ELEMENT, parser); + + final ElementParams elementParams = new ElementParams(); + final int elementName = a.getInt( + R.styleable.KeyboardLayoutSet_Element_elementName, 0); + elementParams.mKeyboardXmlId = a.getResourceId( + R.styleable.KeyboardLayoutSet_Element_elementKeyboard, 0); + elementParams.mProximityCharsCorrectionEnabled = a.getBoolean( + R.styleable.KeyboardLayoutSet_Element_enableProximityCharsCorrection, + false); + mParams.mKeyboardLayoutSetElementIdToParamsMap.put(elementName, elementParams); + } finally { + a.recycle(); + } + } + + private static int getKeyboardMode(EditorInfo editorInfo) { + if (editorInfo == null) + return KeyboardId.MODE_TEXT; + + final int inputType = editorInfo.inputType; + final int variation = inputType & InputType.TYPE_MASK_VARIATION; + + switch (inputType & InputType.TYPE_MASK_CLASS) { + case InputType.TYPE_CLASS_NUMBER: + return KeyboardId.MODE_NUMBER; + case InputType.TYPE_CLASS_DATETIME: + switch (variation) { + case InputType.TYPE_DATETIME_VARIATION_DATE: + return KeyboardId.MODE_DATE; + case InputType.TYPE_DATETIME_VARIATION_TIME: + return KeyboardId.MODE_TIME; + default: // InputType.TYPE_DATETIME_VARIATION_NORMAL + return KeyboardId.MODE_DATETIME; + } + case InputType.TYPE_CLASS_PHONE: + return KeyboardId.MODE_PHONE; + case InputType.TYPE_CLASS_TEXT: + if (InputTypeUtils.isEmailVariation(variation)) { + return KeyboardId.MODE_EMAIL; + } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) { + return KeyboardId.MODE_URL; + } else if (variation == InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE) { + return KeyboardId.MODE_IM; + } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) { + return KeyboardId.MODE_TEXT; + } else { + return KeyboardId.MODE_TEXT; + } + default: + return KeyboardId.MODE_TEXT; + } + } + } +} diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java deleted file mode 100644 index f9b6b72c7..000000000 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.inputmethod.keyboard; - -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.text.InputType; -import android.util.Log; -import android.util.Xml; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodSubtype; - -import com.android.inputmethod.compat.EditorInfoCompatUtils; -import com.android.inputmethod.keyboard.KeyboardSet.Params.ElementParams; -import com.android.inputmethod.latin.InputTypeUtils; -import com.android.inputmethod.latin.LatinIME; -import com.android.inputmethod.latin.LatinImeLogger; -import com.android.inputmethod.latin.LocaleUtils.RunInLocale; -import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.StringUtils; -import com.android.inputmethod.latin.SubtypeLocale; -import com.android.inputmethod.latin.XmlParseUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.lang.ref.SoftReference; -import java.util.HashMap; -import java.util.Locale; - -/** - * This class represents a set of keyboards. Each of them represents a different keyboard - * specific to a keyboard state, such as alphabet, symbols, and so on. Layouts in the same - * {@link KeyboardSet} are related to each other. - * A {@link KeyboardSet} needs to be created for each {@link android.view.inputmethod.EditorInfo}. - */ -public class KeyboardSet { - private static final String TAG = KeyboardSet.class.getSimpleName(); - private static final boolean DEBUG_CACHE = LatinImeLogger.sDBG; - - private static final String TAG_KEYBOARD_SET = "KeyboardSet"; - private static final String TAG_ELEMENT = "Element"; - - private final Context mContext; - private final Params mParams; - - private static final HashMap> sKeyboardCache = - new HashMap>(); - private static final KeysCache sKeysCache = new KeysCache(); - - public static class KeyboardSetException extends RuntimeException { - public final KeyboardId mKeyboardId; - - public KeyboardSetException(Throwable cause, KeyboardId keyboardId) { - super(cause); - mKeyboardId = keyboardId; - } - } - - public static class KeysCache { - private final HashMap mMap; - - public KeysCache() { - mMap = new HashMap(); - } - - public void clear() { - mMap.clear(); - } - - public Key get(Key key) { - final Key existingKey = mMap.get(key); - if (existingKey != null) { - // Reuse the existing element that equals to "key" without adding "key" to the map. - return existingKey; - } - mMap.put(key, key); - return key; - } - } - - static class Params { - int mMode; - EditorInfo mEditorInfo; - boolean mTouchPositionCorrectionEnabled; - boolean mVoiceKeyEnabled; - boolean mVoiceKeyOnMain; - boolean mNoSettingsKey; - boolean mLanguageSwitchKeyEnabled; - Locale mLocale; - int mOrientation; - int mWidth; - // KeyboardSet element id to element's parameters map. - final HashMap mKeyboardSetElementIdToParamsMap = - new HashMap(); - - static class ElementParams { - int mKeyboardXmlId; - boolean mProximityCharsCorrectionEnabled; - } - } - - public static void clearKeyboardCache() { - sKeyboardCache.clear(); - sKeysCache.clear(); - } - - private KeyboardSet(Context context, Params params) { - mContext = context; - mParams = params; - } - - public Keyboard getKeyboard(int baseKeyboardSetElementId) { - final int keyboardSetElementId; - switch (mParams.mMode) { - case KeyboardId.MODE_PHONE: - if (baseKeyboardSetElementId == KeyboardId.ELEMENT_SYMBOLS) { - keyboardSetElementId = KeyboardId.ELEMENT_PHONE_SYMBOLS; - } else { - keyboardSetElementId = KeyboardId.ELEMENT_PHONE; - } - break; - case KeyboardId.MODE_NUMBER: - case KeyboardId.MODE_DATE: - case KeyboardId.MODE_TIME: - case KeyboardId.MODE_DATETIME: - keyboardSetElementId = KeyboardId.ELEMENT_NUMBER; - break; - default: - keyboardSetElementId = baseKeyboardSetElementId; - break; - } - - ElementParams elementParams = mParams.mKeyboardSetElementIdToParamsMap.get( - keyboardSetElementId); - if (elementParams == null) { - elementParams = mParams.mKeyboardSetElementIdToParamsMap.get( - KeyboardId.ELEMENT_ALPHABET); - } - final KeyboardId id = getKeyboardId(keyboardSetElementId); - try { - return getKeyboard(mContext, elementParams, id); - } catch (RuntimeException e) { - throw new KeyboardSetException(e, id); - } - } - - private Keyboard getKeyboard(Context context, ElementParams elementParams, - final KeyboardId id) { - final SoftReference ref = sKeyboardCache.get(id); - Keyboard keyboard = (ref == null) ? null : ref.get(); - if (keyboard == null) { - final Keyboard.Builder builder = - new Keyboard.Builder(mContext, new Keyboard.Params()); - if (id.isAlphabetKeyboard()) { - builder.setAutoGenerate(sKeysCache); - } - final int keyboardXmlId = elementParams.mKeyboardXmlId; - final RunInLocale job = new RunInLocale() { - @Override - protected Void job(Resources res) { - builder.load(keyboardXmlId, id); - return null; - } - }; - job.runInLocale(context.getResources(), id.mLocale); - builder.setTouchPositionCorrectionEnabled(mParams.mTouchPositionCorrectionEnabled); - builder.setProximityCharsCorrectionEnabled( - elementParams.mProximityCharsCorrectionEnabled); - keyboard = builder.build(); - sKeyboardCache.put(id, new SoftReference(keyboard)); - - if (DEBUG_CACHE) { - Log.d(TAG, "keyboard cache size=" + sKeyboardCache.size() + ": " - + ((ref == null) ? "LOAD" : "GCed") + " id=" + id); - } - } else if (DEBUG_CACHE) { - Log.d(TAG, "keyboard cache size=" + sKeyboardCache.size() + ": HIT id=" + id); - } - - return keyboard; - } - - // Note: The keyboard for each locale, shift state, and mode are represented as KeyboardSet - // element id that is a key in keyboard_set.xml. Also that file specifies which XML layout - // should be used for each keyboard. The KeyboardId is an internal key for Keyboard object. - private KeyboardId getKeyboardId(int keyboardSetElementId) { - final Params params = mParams; - final boolean isSymbols = (keyboardSetElementId == KeyboardId.ELEMENT_SYMBOLS - || keyboardSetElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED); - final boolean noLanguage = params.mLocale.getLanguage().equals(SubtypeLocale.NO_LANGUAGE); - final boolean voiceKeyEnabled = params.mVoiceKeyEnabled && !noLanguage; - final boolean hasShortcutKey = voiceKeyEnabled && (isSymbols != params.mVoiceKeyOnMain); - return new KeyboardId(keyboardSetElementId, params.mLocale, params.mOrientation, - params.mWidth, params.mMode, params.mEditorInfo, params.mNoSettingsKey, - voiceKeyEnabled, hasShortcutKey, params.mLanguageSwitchKeyEnabled); - } - - public static class Builder { - private final Context mContext; - private final String mPackageName; - private final Resources mResources; - private final EditorInfo mEditorInfo; - - private final Params mParams = new Params(); - - private static final EditorInfo EMPTY_EDITOR_INFO = new EditorInfo(); - - public Builder(Context context, EditorInfo editorInfo) { - mContext = context; - mPackageName = context.getPackageName(); - mResources = context.getResources(); - mEditorInfo = editorInfo; - final Params params = mParams; - - params.mMode = getKeyboardMode(editorInfo); - params.mEditorInfo = (editorInfo != null) ? editorInfo : EMPTY_EDITOR_INFO; - params.mNoSettingsKey = StringUtils.inPrivateImeOptions( - mPackageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, mEditorInfo); - } - - public Builder setScreenGeometry(int orientation, int widthPixels) { - mParams.mOrientation = orientation; - mParams.mWidth = widthPixels; - return this; - } - - public Builder setSubtype(InputMethodSubtype subtype) { - final Locale inputLocale = SubtypeLocale.getSubtypeLocale(subtype); - final boolean asciiCapable = subtype.containsExtraValueKey( - LatinIME.SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE); - final boolean deprecatedForceAscii = StringUtils.inPrivateImeOptions( - mPackageName, LatinIME.IME_OPTION_FORCE_ASCII, mEditorInfo); - final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii( - mParams.mEditorInfo.imeOptions) - || deprecatedForceAscii; - mParams.mLocale = (forceAscii && !asciiCapable) - ? SubtypeLocale.LOCALE_NO_LANGUAGE_QWERTY : inputLocale; - return this; - } - - public Builder setOptions(boolean voiceKeyEnabled, boolean voiceKeyOnMain, - boolean languageSwitchKeyEnabled) { - @SuppressWarnings("deprecation") - final boolean deprecatedNoMicrophone = StringUtils.inPrivateImeOptions( - null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, mEditorInfo); - final boolean noMicrophone = StringUtils.inPrivateImeOptions( - mPackageName, LatinIME.IME_OPTION_NO_MICROPHONE, mEditorInfo) - || deprecatedNoMicrophone; - mParams.mVoiceKeyEnabled = voiceKeyEnabled && !noMicrophone; - mParams.mVoiceKeyOnMain = voiceKeyOnMain; - mParams.mLanguageSwitchKeyEnabled = languageSwitchKeyEnabled; - return this; - } - - public void setTouchPositionCorrectionEnabled(boolean enabled) { - mParams.mTouchPositionCorrectionEnabled = enabled; - } - - public KeyboardSet build() { - if (mParams.mOrientation == Configuration.ORIENTATION_UNDEFINED) - throw new RuntimeException("Screen geometry is not specified"); - if (mParams.mLocale == null) - throw new RuntimeException("KeyboardSet subtype is not specified"); - - final RunInLocale job = new RunInLocale() { - @Override - protected Void job(Resources res) { - try { - parseKeyboardSet(res, R.xml.keyboard_set); - } catch (Exception e) { - throw new RuntimeException(e.getMessage() + " in " - + res.getResourceName(R.xml.keyboard_set) - + " of locale " + mParams.mLocale); - } - return null; - } - }; - job.runInLocale(mResources, mParams.mLocale); - return new KeyboardSet(mContext, mParams); - } - - private void parseKeyboardSet(Resources res, int resId) throws XmlPullParserException, - IOException { - final XmlResourceParser parser = res.getXml(resId); - try { - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { - if (event == XmlPullParser.START_TAG) { - final String tag = parser.getName(); - if (TAG_KEYBOARD_SET.equals(tag)) { - parseKeyboardSetContent(parser); - } else { - throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD_SET); - } - } - } - } finally { - parser.close(); - } - } - - private void parseKeyboardSetContent(XmlPullParser parser) throws XmlPullParserException, - IOException { - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { - if (event == XmlPullParser.START_TAG) { - final String tag = parser.getName(); - if (TAG_ELEMENT.equals(tag)) { - parseKeyboardSetElement(parser); - } else { - throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD_SET); - } - } else if (event == XmlPullParser.END_TAG) { - final String tag = parser.getName(); - if (TAG_KEYBOARD_SET.equals(tag)) { - break; - } else { - throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEYBOARD_SET); - } - } - } - } - - private void parseKeyboardSetElement(XmlPullParser parser) throws XmlPullParserException, - IOException { - final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), - R.styleable.KeyboardSet_Element); - try { - XmlParseUtils.checkAttributeExists(a, - R.styleable.KeyboardSet_Element_elementName, "elementName", - TAG_ELEMENT, parser); - XmlParseUtils.checkAttributeExists(a, - R.styleable.KeyboardSet_Element_elementKeyboard, "elementKeyboard", - TAG_ELEMENT, parser); - XmlParseUtils.checkEndTag(TAG_ELEMENT, parser); - - final ElementParams elementParams = new ElementParams(); - final int elementName = a.getInt( - R.styleable.KeyboardSet_Element_elementName, 0); - elementParams.mKeyboardXmlId = a.getResourceId( - R.styleable.KeyboardSet_Element_elementKeyboard, 0); - elementParams.mProximityCharsCorrectionEnabled = a.getBoolean( - R.styleable.KeyboardSet_Element_enableProximityCharsCorrection, false); - mParams.mKeyboardSetElementIdToParamsMap.put(elementName, elementParams); - } finally { - a.recycle(); - } - } - - private static int getKeyboardMode(EditorInfo editorInfo) { - if (editorInfo == null) - return KeyboardId.MODE_TEXT; - - final int inputType = editorInfo.inputType; - final int variation = inputType & InputType.TYPE_MASK_VARIATION; - - switch (inputType & InputType.TYPE_MASK_CLASS) { - case InputType.TYPE_CLASS_NUMBER: - return KeyboardId.MODE_NUMBER; - case InputType.TYPE_CLASS_DATETIME: - switch (variation) { - case InputType.TYPE_DATETIME_VARIATION_DATE: - return KeyboardId.MODE_DATE; - case InputType.TYPE_DATETIME_VARIATION_TIME: - return KeyboardId.MODE_TIME; - default: // InputType.TYPE_DATETIME_VARIATION_NORMAL - return KeyboardId.MODE_DATETIME; - } - case InputType.TYPE_CLASS_PHONE: - return KeyboardId.MODE_PHONE; - case InputType.TYPE_CLASS_TEXT: - if (InputTypeUtils.isEmailVariation(variation)) { - return KeyboardId.MODE_EMAIL; - } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) { - return KeyboardId.MODE_URL; - } else if (variation == InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE) { - return KeyboardId.MODE_IM; - } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) { - return KeyboardId.MODE_TEXT; - } else { - return KeyboardId.MODE_TEXT; - } - default: - return KeyboardId.MODE_TEXT; - } - } - } -} diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 3bc63f3dd..e50d922ea 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -27,7 +27,7 @@ import android.view.View; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; -import com.android.inputmethod.keyboard.KeyboardSet.KeyboardSetException; +import com.android.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetException; import com.android.inputmethod.keyboard.PointerTracker.TimerProxy; import com.android.inputmethod.keyboard.internal.KeyboardState; import com.android.inputmethod.latin.DebugSettings; @@ -76,7 +76,7 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions { private KeyboardState mState; - private KeyboardSet mKeyboardSet; + private KeyboardLayoutSet mKeyboardLayoutSet; /** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of * what user actually typed. */ @@ -129,12 +129,13 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions { if (mKeyboardTheme.mThemeId != keyboardTheme.mThemeId) { mKeyboardTheme = keyboardTheme; mThemeContext = new ContextThemeWrapper(context, keyboardTheme.mStyleId); - KeyboardSet.clearKeyboardCache(); + KeyboardLayoutSet.clearKeyboardCache(); } } public void loadKeyboard(EditorInfo editorInfo, SettingsValues settingsValues) { - final KeyboardSet.Builder builder = new KeyboardSet.Builder(mThemeContext, editorInfo); + final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder( + mThemeContext, editorInfo); builder.setScreenGeometry(mThemeContext.getResources().getConfiguration().orientation, mThemeContext.getResources().getDisplayMetrics().widthPixels); builder.setSubtype(mSubtypeSwitcher.getCurrentSubtype()); @@ -142,10 +143,10 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions { settingsValues.isVoiceKeyEnabled(editorInfo), settingsValues.isVoiceKeyOnMain(), settingsValues.isLanguageSwitchKeyEnabled(mThemeContext)); - mKeyboardSet = builder.build(); + mKeyboardLayoutSet = builder.build(); try { mState.onLoadKeyboard(mResources.getString(R.string.layout_switch_back_symbols)); - } catch (KeyboardSetException e) { + } catch (KeyboardLayoutSetException e) { Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause()); LatinImeLogger.logOnException(e.mKeyboardId.toString(), e.getCause()); return; @@ -214,43 +215,43 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions { // Implements {@link KeyboardState.SwitchActions}. @Override public void setAlphabetKeyboard() { - setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET)); + setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET)); } // Implements {@link KeyboardState.SwitchActions}. @Override public void setAlphabetManualShiftedKeyboard() { - setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED)); + setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED)); } // Implements {@link KeyboardState.SwitchActions}. @Override public void setAlphabetAutomaticShiftedKeyboard() { - setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED)); + setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED)); } // Implements {@link KeyboardState.SwitchActions}. @Override public void setAlphabetShiftLockedKeyboard() { - setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED)); + setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED)); } // Implements {@link KeyboardState.SwitchActions}. @Override public void setAlphabetShiftLockShiftedKeyboard() { - setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED)); + setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED)); } // Implements {@link KeyboardState.SwitchActions}. @Override public void setSymbolsKeyboard() { - setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS)); + setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS)); } // Implements {@link KeyboardState.SwitchActions}. @Override public void setSymbolsShiftedKeyboard() { - setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS_SHIFTED)); + setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS_SHIFTED)); } // Implements {@link KeyboardState.SwitchActions}. diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java index 0aba813b2..4abd887f0 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java @@ -318,7 +318,7 @@ public class KeySpecParser { } } - private static int getResourceId(Resources res, String name, int packageNameResId) { + public static int getResourceId(Resources res, String name, int packageNameResId) { String packageName = res.getResourcePackageName(packageNameResId); int resId = res.getIdentifier(name, null, packageName); if (resId == 0) { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 8a26d2b9e..f5c09974e 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -115,16 +115,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public static final String IME_OPTION_FORCE_ASCII = "forceAscii"; /** - * The subtype extra value used to indicate that the subtype keyboard layout is capable for - * typing ASCII characters. + * The subtype extra value used to indicate that the subtype keyboard layout set name. */ - public static final String SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable"; + public static final String SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET = "KeyboardLayoutSet"; /** - * The subtype extra value used to indicate that the subtype keyboard layout should be loaded - * from the specified locale. + * The subtype extra value used to indicate that the subtype keyboard layout is capable for + * typing ASCII characters. */ - public static final String SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE = "KeyboardLocale"; + public static final String SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable"; private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100; diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index 7000e4633..42fce53d0 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -22,6 +22,7 @@ import android.view.inputmethod.EditorInfo; import com.android.inputmethod.keyboard.Keyboard; import java.util.ArrayList; +import java.util.Locale; public class StringUtils { private StringUtils() { @@ -149,4 +150,20 @@ public class StringUtils { i++; } } + + public static String toTitleCase(String s, Locale locale) { + if (s.length() <= 1) { + // TODO: is this really correct? Shouldn't this be s.toUpperCase()? + return s; + } + // TODO: fix the bugs below + // - This does not work for Greek, because it returns upper case instead of title case. + // - It does not work for Serbian, because it fails to account for the "lj" character, + // which should be "Lj" in title case and "LJ" in upper case. + // - It does not work for Dutch, because it fails to account for the "ij" digraph, which + // are two different characters but both should be capitalized as "IJ" as if they were + // a single letter. + // - It also does not work with unicode surrogate code points. + return s.toUpperCase(locale).charAt(0) + s.substring(1); + } } diff --git a/java/src/com/android/inputmethod/latin/SubtypeLocale.java b/java/src/com/android/inputmethod/latin/SubtypeLocale.java index fac74f0b5..2bc22a6f9 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeLocale.java +++ b/java/src/com/android/inputmethod/latin/SubtypeLocale.java @@ -18,7 +18,7 @@ package com.android.inputmethod.latin; import android.content.Context; import android.content.res.Resources; -import android.view.inputmethod.InputMethodSubtype; + import java.util.Locale; @@ -69,10 +69,10 @@ public class SubtypeLocale { } final String value = lookupExceptionalLocale(key); if (value == null) { - return toTitleCase(locale.getDisplayName(locale), locale); + return StringUtils.toTitleCase(locale.getDisplayName(locale), locale); } if (value.indexOf("%s") >= 0) { - final String languageName = toTitleCase(locale.getDisplayLanguage(locale), locale); + final String languageName = StringUtils.toTitleCase(locale.getDisplayLanguage(locale), locale); return String.format(value, languageName); } return value; @@ -88,7 +88,7 @@ public class SubtypeLocale { if (NO_LANGUAGE.equals(locale.getLanguage())) { return lookupExceptionalLocale(locale.getCountry()); } else { - return toTitleCase(locale.getDisplayLanguage(locale), locale); + return StringUtils.toTitleCase(locale.getDisplayLanguage(locale), locale); } } @@ -102,33 +102,7 @@ public class SubtypeLocale { if (NO_LANGUAGE.equals(locale.getLanguage())) { return locale.getCountry(); } else { - return toTitleCase(locale.getLanguage(), locale); - } - } - - public static String toTitleCase(String s, Locale locale) { - if (s.length() <= 1) { - // TODO: is this really correct? Shouldn't this be s.toUpperCase()? - return s; + return StringUtils.toTitleCase(locale.getLanguage(), locale); } - // TODO: fix the bugs below - // - This does not work for Greek, because it returns upper case instead of title case. - // - It does not work for Serbian, because it fails to account for the "lj" character, - // which should be "Lj" in title case and "LJ" in upper case. - // - It does not work for Dutch, because it fails to account for the "ij" digraph, which - // are two different characters but both should be capitalized as "IJ" as if they were - // a single letter. - // - It also does not work with unicode surrogate code points. - return s.toUpperCase(locale).charAt(0) + s.substring(1); - } - - public static String getSubtypeLocaleString(InputMethodSubtype subtype) { - final String keyboardLocale = subtype.getExtraValueOf( - LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE); - return keyboardLocale != null ? keyboardLocale : subtype.getLocale(); - } - - public static Locale getSubtypeLocale(InputMethodSubtype subtype) { - return LocaleUtils.constructLocaleFromString(getSubtypeLocaleString(subtype)); } } diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index 3ed7f8700..dfb01a24c 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -33,6 +33,7 @@ import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; +import com.android.inputmethod.keyboard.KeyboardLayoutSet; import com.android.inputmethod.keyboard.KeyboardSwitcher; import java.util.ArrayList; @@ -68,6 +69,7 @@ public class SubtypeSwitcher { private InputMethodInfo mShortcutInputMethodInfo; private InputMethodSubtype mShortcutSubtype; private List mAllEnabledSubtypesOfCurrentInputMethod; + private InputMethodSubtype mNoLanguageSubtype; // Note: This variable is always non-null after {@link #initialize(LatinIME)}. private InputMethodSubtype mCurrentSubtype; private Locale mSystemLocale; @@ -104,6 +106,8 @@ public class SubtypeSwitcher { mInputLocaleStr = null; mCurrentSubtype = mImm.getCurrentInputMethodSubtype(); mAllEnabledSubtypesOfCurrentInputMethod = null; + mNoLanguageSubtype = SubtypeUtils.findSubtypeByKeyboardLayoutSetLocale( + service, SubtypeLocale.LOCALE_NO_LANGUAGE_QWERTY); final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); mIsNetworkConnected = (info != null && info.isConnected()); @@ -133,7 +137,7 @@ public class SubtypeSwitcher { mEnabledLanguagesOfCurrentInputMethod.clear(); mEnabledKeyboardSubtypesOfCurrentInputMethod.clear(); for (InputMethodSubtype ims : mAllEnabledSubtypesOfCurrentInputMethod) { - final String locale = getSubtypeLocale(ims); + final String locale = KeyboardLayoutSet.getKeyboardLayoutSetLocaleString(ims); final String mode = ims.getMode(); mLocaleSplitter.setString(locale); if (mLocaleSplitter.hasNext()) { @@ -162,7 +166,8 @@ public class SubtypeSwitcher { Log.d(TAG, "Update shortcut IME from : " + (mShortcutInputMethodInfo == null ? "" : mShortcutInputMethodInfo.getId()) + ", " - + (mShortcutSubtype == null ? "" : (getSubtypeLocale(mShortcutSubtype) + + (mShortcutSubtype == null ? "" : ( + KeyboardLayoutSet.getKeyboardLayoutSetLocaleString(mShortcutSubtype) + ", " + mShortcutSubtype.getMode()))); } // TODO: Update an icon for shortcut IME @@ -184,20 +189,15 @@ public class SubtypeSwitcher { Log.d(TAG, "Update shortcut IME to : " + (mShortcutInputMethodInfo == null ? "" : mShortcutInputMethodInfo.getId()) + ", " - + (mShortcutSubtype == null ? "" : (getSubtypeLocale(mShortcutSubtype) + + (mShortcutSubtype == null ? "" : ( + KeyboardLayoutSet.getKeyboardLayoutSetLocaleString(mShortcutSubtype) + ", " + mShortcutSubtype.getMode()))); } } - private static String getSubtypeLocale(InputMethodSubtype subtype) { - final String keyboardLocale = subtype.getExtraValueOf( - LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE); - return keyboardLocale != null ? keyboardLocale : subtype.getLocale(); - } - // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function. public void updateSubtype(InputMethodSubtype newSubtype) { - final String newLocale = getSubtypeLocale(newSubtype); + final String newLocale = KeyboardLayoutSet.getKeyboardLayoutSetLocaleString(newSubtype); final String newMode = newSubtype.getMode(); final String oldMode = getCurrentSubtypeMode(); if (DBG) { @@ -301,7 +301,8 @@ public class SubtypeSwitcher { final String imiPackageName = imi.getPackageName(); if (DBG) { Log.d(TAG, "Update icons of IME: " + imiPackageName + "," - + getSubtypeLocale(subtype) + "," + subtype.getMode()); + + KeyboardLayoutSet.getKeyboardLayoutSetLocaleString(subtype) + "," + + subtype.getMode()); } if (subtype != null) { return pm.getDrawable(imiPackageName, subtype.getIconResId(), @@ -438,4 +439,8 @@ public class SubtypeSwitcher { public InputMethodSubtype getCurrentSubtype() { return mCurrentSubtype; } + + public InputMethodSubtype getNoLanguageSubtype() { + return mNoLanguageSubtype; + } } diff --git a/java/src/com/android/inputmethod/latin/SubtypeUtils.java b/java/src/com/android/inputmethod/latin/SubtypeUtils.java index 2c5d58200..a747c9ad7 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeUtils.java +++ b/java/src/com/android/inputmethod/latin/SubtypeUtils.java @@ -21,9 +21,11 @@ import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; +import com.android.inputmethod.keyboard.KeyboardLayoutSet; import java.util.Collections; import java.util.List; +import java.util.Locale; public class SubtypeUtils { private SubtypeUtils() { @@ -129,4 +131,18 @@ public class SubtypeUtils { } throw new RuntimeException("Can not find input method id for " + packageName); } + + public static InputMethodSubtype findSubtypeByKeyboardLayoutSetLocale( + Context context, Locale locale) { + final String localeString = locale.toString(); + final InputMethodInfo imi = SubtypeUtils.getInputMethodInfo(context.getPackageName()); + final int count = imi.getSubtypeCount(); + for (int i = 0; i < count; i++) { + final InputMethodSubtype subtype = imi.getSubtypeAt(i); + if (localeString.equals(KeyboardLayoutSet.getKeyboardLayoutSetLocaleString(subtype))) { + return subtype; + } + } + throw new RuntimeException("Can not find subtype of locale " + localeString); + } } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index cd01bb146..1fc945f3c 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -37,7 +37,6 @@ import com.android.inputmethod.latin.Flag; import com.android.inputmethod.latin.LocaleUtils; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StringUtils; -import com.android.inputmethod.latin.SubtypeLocale; import com.android.inputmethod.latin.SynchronouslyLoadedContactsDictionary; import com.android.inputmethod.latin.SynchronouslyLoadedUserDictionary; import com.android.inputmethod.latin.WhitelistDictionary; @@ -326,7 +325,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService } else if (CAPITALIZE_FIRST == capitalizeType) { for (int i = 0; i < mSuggestions.size(); ++i) { // Likewise - mSuggestions.set(i, SubtypeLocale.toTitleCase( + mSuggestions.set(i, StringUtils.toTitleCase( mSuggestions.get(i).toString(), locale)); } } diff --git a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java index 6180ff5f9..4ac765782 100644 --- a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java +++ b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java @@ -22,6 +22,8 @@ import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; +import com.android.inputmethod.keyboard.KeyboardLayoutSet; + import java.util.ArrayList; import java.util.Locale; @@ -58,29 +60,17 @@ public class SubtypeLocaleTests extends AndroidTestCase { assertTrue("Can not find keyboard subtype", mSubtypesList.size() > 0); } - private static Locale getSubtypeLocale(InputMethodSubtype subtype) { - return LocaleUtils.constructLocaleFromString(subtype.getLocale()); - } - - private static Locale getKeyboardLocale(InputMethodSubtype subtype) { - final String subtypeLocaleString = subtype.containsExtraValueKey( - LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE) - ? subtype.getExtraValueOf(LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE) - : subtype.getLocale(); - return LocaleUtils.constructLocaleFromString(subtypeLocaleString); - } - public void testFullDisplayName() { final StringBuilder messages = new StringBuilder(); int failedCount = 0; for (final InputMethodSubtype subtype : mSubtypesList) { - final Locale locale = getKeyboardLocale(subtype); + final Locale locale = KeyboardLayoutSet.getKeyboardLayoutSetLocale(subtype); if (locale.getLanguage().equals(SubtypeLocale.NO_LANGUAGE)) { // This is special language name for language agnostic usage. continue; } final String keyboardName = SubtypeLocale.getFullDisplayName(locale); - final String languageName = SubtypeLocale.toTitleCase( + final String languageName = StringUtils.toTitleCase( locale.getDisplayLanguage(locale), locale); if (!keyboardName.contains(languageName)) { failedCount++; @@ -104,13 +94,13 @@ public class SubtypeLocaleTests extends AndroidTestCase { final StringBuilder messages = new StringBuilder(); int failedCount = 0; for (final InputMethodSubtype subtype : mSubtypesList) { - final Locale locale = getKeyboardLocale(subtype); + final Locale locale = KeyboardLayoutSet.getKeyboardLayoutSetLocale(subtype); if (locale.getLanguage().equals(SubtypeLocale.NO_LANGUAGE)) { // This is special language name for language agnostic usage. continue; } final String keyboardName = SubtypeLocale.getMiddleDisplayName(locale); - final String languageName = SubtypeLocale.toTitleCase( + final String languageName = StringUtils.toTitleCase( locale.getDisplayLanguage(locale), locale); if (!keyboardName.equals(languageName)) { failedCount++; @@ -131,13 +121,13 @@ public class SubtypeLocaleTests extends AndroidTestCase { final StringBuilder messages = new StringBuilder(); int failedCount = 0; for (final InputMethodSubtype subtype : mSubtypesList) { - final Locale locale = getKeyboardLocale(subtype); + final Locale locale = KeyboardLayoutSet.getKeyboardLayoutSetLocale(subtype); if (locale.getCountry().equals(SubtypeLocale.QWERTY)) { // This is special country code for QWERTY keyboard. continue; } final String keyboardName = SubtypeLocale.getShortDisplayName(locale); - final String languageCode = SubtypeLocale.toTitleCase(locale.getLanguage(), locale); + final String languageCode = StringUtils.toTitleCase(locale.getLanguage(), locale); if (!keyboardName.equals(languageCode)) { failedCount++; messages.append(String.format( -- cgit v1.2.3-83-g751a From a4c7733cf7b5c0f970d1a8e52ee52b6199f56031 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Fri, 6 Apr 2012 11:49:48 +0900 Subject: Cleanup unused methods Change-Id: Ic7c1ec0e0606da6eb5b954934547c6e8a561fed5 --- .../com/android/inputmethod/keyboard/Keyboard.java | 2 +- .../com/android/inputmethod/latin/StringUtils.java | 4 +- .../android/inputmethod/latin/SubtypeSwitcher.java | 43 +--------------------- 3 files changed, 4 insertions(+), 45 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/StringUtils.java') diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 6ada09067..950b5e99b 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -1229,7 +1229,7 @@ public class Keyboard { private void endRow(Row row) { if (mCurrentRow == null) - throw new InflateException("orphant end row tag"); + throw new InflateException("orphan end row tag"); if (mRightEdgeKey != null) { mRightEdgeKey.markAsRightEdge(mParams); mRightEdgeKey = null; diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index 42fce53d0..649cd650a 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -46,7 +46,7 @@ public class StringUtils { return text.codePointCount(0, text.length()); } - public static boolean containsInCsv(String key, String csv) { + private static boolean containsInCsv(String key, String csv) { if (csv == null) return false; for (String option : csv.split(",")) { @@ -129,7 +129,7 @@ public class StringUtils { /** * Remove duplicates from an array of strings. * - * This method will always keep the first occurence of all strings at their position + * This method will always keep the first occurrence of all strings at their position * in the array, removing the subsequent ones. */ public static void removeDupes(final ArrayList suggestions) { diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index dfb01a24c..6612c24cd 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -18,11 +18,9 @@ package com.android.inputmethod.latin; import android.content.Context; import android.content.Intent; -import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.content.res.Resources; -import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.AsyncTask; @@ -291,45 +289,6 @@ public class SubtypeSwitcher { }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } - public Drawable getShortcutIcon() { - return getSubtypeIcon(mShortcutInputMethodInfo, mShortcutSubtype); - } - - private Drawable getSubtypeIcon(InputMethodInfo imi, InputMethodSubtype subtype) { - final PackageManager pm = mService.getPackageManager(); - if (imi != null) { - final String imiPackageName = imi.getPackageName(); - if (DBG) { - Log.d(TAG, "Update icons of IME: " + imiPackageName + "," - + KeyboardLayoutSet.getKeyboardLayoutSetLocaleString(subtype) + "," - + subtype.getMode()); - } - if (subtype != null) { - return pm.getDrawable(imiPackageName, subtype.getIconResId(), - imi.getServiceInfo().applicationInfo); - } else if (imi.getSubtypeCount() > 0 && imi.getSubtypeAt(0) != null) { - return pm.getDrawable(imiPackageName, - imi.getSubtypeAt(0).getIconResId(), - imi.getServiceInfo().applicationInfo); - } else { - try { - return pm.getApplicationInfo(imiPackageName, 0).loadIcon(pm); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "IME can't be found: " + imiPackageName); - } - } - } - return null; - } - - private static boolean contains(String[] hay, String needle) { - for (String element : hay) { - if (element.equals(needle)) - return true; - } - return false; - } - public boolean isShortcutImeEnabled() { if (mShortcutInputMethodInfo == null) { return false; @@ -352,7 +311,7 @@ public class SubtypeSwitcher { return false; if (mShortcutSubtype == null) return true; - if (contains(mShortcutSubtype.getExtraValue().split(","), + if (mShortcutSubtype.containsExtraValueKey( SUBTYPE_EXTRAVALUE_REQUIRE_NETWORK_CONNECTIVITY)) { return mIsNetworkConnected; } -- cgit v1.2.3-83-g751a From 80111f08e284655808380663f0b68547b981da72 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 17 Apr 2012 15:55:17 +0900 Subject: Pass the previous word down to native code in getSuggestions Change-Id: I477b631d81ef58461e44954f3ae5fd895928bb97 --- .../com/android/inputmethod/latin/BinaryDictionary.java | 9 ++++++--- java/src/com/android/inputmethod/latin/StringUtils.java | 15 +++++++++++++++ .../com_android_inputmethod_latin_BinaryDictionary.cpp | 12 +++++++++--- native/jni/src/bigram_dictionary.cpp | 1 - 4 files changed, 30 insertions(+), 7 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/StringUtils.java') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index f4c8e61ed..9429ef411 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -85,8 +85,8 @@ public class BinaryDictionary extends Dictionary { private native void closeNative(long dict); private native boolean isValidWordNative(long dict, char[] word, int wordLength); private native int getSuggestionsNative(long dict, long proximityInfo, int[] xCoordinates, - int[] yCoordinates, int[] inputCodes, int codesSize, boolean useFullEditDistance, - char[] outputChars, int[] scores); + int[] yCoordinates, int[] inputCodes, int codesSize, int[] prevWordForBigrams, + boolean useFullEditDistance, char[] outputChars, int[] scores); private native int getBigramsNative(long dict, char[] prevWord, int prevWordLength, int[] inputCodes, int inputCodesLength, char[] outputChars, int[] scores, int maxWordLength, int maxBigrams); @@ -177,11 +177,14 @@ public class BinaryDictionary extends Dictionary { Arrays.fill(outputChars, (char) 0); Arrays.fill(scores, 0); + final int[] prevWordCodePointArray = null == prevWordForBigrams + ? null : StringUtils.toCodePointArray(prevWordForBigrams.toString()); + // TODO: pass the previous word to native code return getSuggestionsNative( mNativeDict, proximityInfo.getNativeProximityInfo(), codes.getXCoordinates(), codes.getYCoordinates(), mInputCodes, codesSize, - mUseFullEditDistance, outputChars, scores); + prevWordCodePointArray, mUseFullEditDistance, outputChars, scores); } public static double calcNormalizedScore(String before, String after, int score) { diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index 649cd650a..a599933d8 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -166,4 +166,19 @@ public class StringUtils { // - It also does not work with unicode surrogate code points. return s.toUpperCase(locale).charAt(0) + s.substring(1); } + + public static int[] toCodePointArray(final String string) { + final char[] characters = string.toCharArray(); + final int length = characters.length; + final int[] codePoints = new int[Character.codePointCount(characters, 0, length)]; + int codePoint = Character.codePointAt(characters, 0); + int dsti = 0; + for (int srci = Character.charCount(codePoint); + srci < length; srci += Character.charCount(codePoint), ++dsti) { + codePoints[dsti] = codePoint; + codePoint = Character.codePointAt(characters, srci); + } + codePoints[dsti] = codePoint; + return codePoints; + } } diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index 613fbc480..2ef72e1e8 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -127,8 +127,8 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jlong dict, jlong proximityInfo, jintArray xCoordinatesArray, jintArray yCoordinatesArray, - jintArray inputArray, jint arraySize, jboolean useFullEditDistance, - jcharArray outputArray, jintArray frequencyArray) { + jintArray inputArray, jint arraySize, jintArray prevWordForBigrams, + jboolean useFullEditDistance, jcharArray outputArray, jintArray frequencyArray) { Dictionary *dictionary = (Dictionary*)dict; if (!dictionary) return 0; ProximityInfo *pInfo = (ProximityInfo*)proximityInfo; @@ -137,6 +137,11 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, int *frequencies = env->GetIntArrayElements(frequencyArray, 0); int *inputCodes = env->GetIntArrayElements(inputArray, 0); jchar *outputChars = env->GetCharArrayElements(outputArray, 0); + // Deactivated to prevent unused variable errors. + // TODO: use the following variables. + // jint *prevWordChars = prevWordForBigrams + // ? env->GetIntArrayElements(prevWordForBigrams, 0) : NULL; + // jsize prevWordLength = prevWordChars ? env->GetArrayLength(prevWordForBigrams) : 0; int count = dictionary->getSuggestions(pInfo, xCoordinates, yCoordinates, inputCodes, arraySize, useFullEditDistance, (unsigned short*) outputChars, frequencies); env->ReleaseCharArrayElements(outputArray, outputChars, 0); @@ -229,7 +234,8 @@ void releaseDictBuf(void* dictBuf, const size_t length, int fd) { static JNINativeMethod sMethods[] = { {"openNative", "(Ljava/lang/String;JJIIII)J", (void*)latinime_BinaryDictionary_open}, {"closeNative", "(J)V", (void*)latinime_BinaryDictionary_close}, - {"getSuggestionsNative", "(JJ[I[I[IIZ[C[I)I", (void*)latinime_BinaryDictionary_getSuggestions}, + {"getSuggestionsNative", "(JJ[I[I[II[IZ[C[I)I", + (void*)latinime_BinaryDictionary_getSuggestions}, {"isValidWordNative", "(J[CI)Z", (void*)latinime_BinaryDictionary_isValidWord}, {"getBigramsNative", "(J[CI[II[C[III)I", (void*)latinime_BinaryDictionary_getBigrams}, {"calcNormalizedScoreNative", "([CI[CII)D", diff --git a/native/jni/src/bigram_dictionary.cpp b/native/jni/src/bigram_dictionary.cpp index 87ca1e9ed..f283cb5c7 100644 --- a/native/jni/src/bigram_dictionary.cpp +++ b/native/jni/src/bigram_dictionary.cpp @@ -30,7 +30,6 @@ BigramDictionary::BigramDictionary(const unsigned char *dict, int maxWordLength, : DICT(dict), MAX_WORD_LENGTH(maxWordLength), mParentDictionary(parentDictionary) { if (DEBUG_DICT) { AKLOGI("BigramDictionary - constructor"); - AKLOGI("Has Bigram : %d", hasBigram); } } -- cgit v1.2.3-83-g751a From 344af156744c6866090fb70f151efd66668c1e20 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Thu, 19 Apr 2012 16:39:25 +0900 Subject: Change predefined additional subtype format in preference This change also refactor StringUtils class Change-Id: Ie0b4d169b21c260bf238d6fcc9ab0ee8bfd6b508 --- java/res/values/predefined-subtypes.xml | 4 +- .../inputmethod/keyboard/KeyboardLayoutSet.java | 10 +-- .../inputmethod/latin/AdditionalSubtype.java | 33 ++++---- .../android/inputmethod/latin/InputAttributes.java | 8 ++ .../com/android/inputmethod/latin/LatinIME.java | 20 ++++- .../android/inputmethod/latin/SettingsValues.java | 8 +- .../com/android/inputmethod/latin/StringUtils.java | 50 ++++++------ .../inputmethod/latin/StringUtilsTests.java | 91 ++++++++++++++++++++++ .../inputmethod/latin/SubtypeLocaleTests.java | 8 +- 9 files changed, 174 insertions(+), 58 deletions(-) create mode 100644 tests/src/com/android/inputmethod/latin/StringUtilsTests.java (limited to 'java/src/com/android/inputmethod/latin/StringUtils.java') diff --git a/java/res/values/predefined-subtypes.xml b/java/res/values/predefined-subtypes.xml index e67fee53f..602f53eac 100644 --- a/java/res/values/predefined-subtypes.xml +++ b/java/res/values/predefined-subtypes.xml @@ -18,6 +18,6 @@ */ --> - - de:qwerty,fr:qwertz + + de:qwerty:AsciiCapable;fr:qwertz:AsciiCapable diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java index 35209e0ad..07f71ee17 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java @@ -29,11 +29,11 @@ import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.compat.EditorInfoCompatUtils; import com.android.inputmethod.keyboard.KeyboardLayoutSet.Params.ElementParams; +import com.android.inputmethod.latin.InputAttributes; import com.android.inputmethod.latin.InputTypeUtils; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.StringUtils; import com.android.inputmethod.latin.SubtypeLocale; import com.android.inputmethod.latin.SubtypeSwitcher; import com.android.inputmethod.latin.XmlParseUtils; @@ -229,7 +229,7 @@ public class KeyboardLayoutSet { params.mMode = getKeyboardMode(editorInfo); params.mEditorInfo = (editorInfo != null) ? editorInfo : EMPTY_EDITOR_INFO; - params.mNoSettingsKey = StringUtils.inPrivateImeOptions( + params.mNoSettingsKey = InputAttributes.inPrivateImeOptions( mPackageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, mEditorInfo); } @@ -242,7 +242,7 @@ public class KeyboardLayoutSet { public Builder setSubtype(InputMethodSubtype subtype) { final boolean asciiCapable = subtype.containsExtraValueKey( LatinIME.SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE); - final boolean deprecatedForceAscii = StringUtils.inPrivateImeOptions( + final boolean deprecatedForceAscii = InputAttributes.inPrivateImeOptions( mPackageName, LatinIME.IME_OPTION_FORCE_ASCII, mEditorInfo); final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii( mParams.mEditorInfo.imeOptions) @@ -259,9 +259,9 @@ public class KeyboardLayoutSet { public Builder setOptions(boolean voiceKeyEnabled, boolean voiceKeyOnMain, boolean languageSwitchKeyEnabled) { @SuppressWarnings("deprecation") - final boolean deprecatedNoMicrophone = StringUtils.inPrivateImeOptions( + final boolean deprecatedNoMicrophone = InputAttributes.inPrivateImeOptions( null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, mEditorInfo); - final boolean noMicrophone = StringUtils.inPrivateImeOptions( + final boolean noMicrophone = InputAttributes.inPrivateImeOptions( mPackageName, LatinIME.IME_OPTION_NO_MICROPHONE, mEditorInfo) || deprecatedNoMicrophone; mParams.mVoiceKeyEnabled = voiceKeyEnabled && !noMicrophone; diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtype.java b/java/src/com/android/inputmethod/latin/AdditionalSubtype.java index b24f06472..323f74ab9 100644 --- a/java/src/com/android/inputmethod/latin/AdditionalSubtype.java +++ b/java/src/com/android/inputmethod/latin/AdditionalSubtype.java @@ -43,28 +43,35 @@ public class AdditionalSubtype { } public static InputMethodSubtype createAdditionalSubtype( - String localeString, String keyboardLayoutSet) { - final String extraValue = String.format( - "%s=%s,%s", LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET, keyboardLayoutSet, - SUBTYPE_EXTRA_VALUE_IS_ADDITIONAL_SUBTYPE); - Integer nameId = sKeyboardLayoutToNameIdsMap.get(keyboardLayoutSet); + String localeString, String keyboardLayoutSetName, String extraValue) { + final String layoutExtraValue = LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET + "=" + + keyboardLayoutSetName; + final String filteredExtraValue = StringUtils.appendToCsvIfNotExists( + SUBTYPE_EXTRA_VALUE_IS_ADDITIONAL_SUBTYPE, + StringUtils.removeFromCsvIfExists(layoutExtraValue, extraValue)); + Integer nameId = sKeyboardLayoutToNameIdsMap.get(keyboardLayoutSetName); if (nameId == null) nameId = R.string.subtype_generic; return new InputMethodSubtype(nameId, R.drawable.ic_subtype_keyboard, - localeString, SUBTYPE_MODE_KEYBOARD, extraValue, false, false); + localeString, SUBTYPE_MODE_KEYBOARD, filteredExtraValue, false, false); } private static final String LOCALE_AND_LAYOUT_SEPARATOR = ":"; - private static final String SUBTYPE_SEPARATOR = ","; + private static final String PREF_SUBTYPE_SEPARATOR = ";"; - public static InputMethodSubtype[] createAdditionalSubtypesArray(String csvSubtypes) { - final String[] subtypeSpecs = csvSubtypes.split(SUBTYPE_SEPARATOR); - final InputMethodSubtype[] subtypesArray = new InputMethodSubtype[subtypeSpecs.length]; - for (int i = 0; i < subtypeSpecs.length; i++) { - final String elems[] = subtypeSpecs[i].split(LOCALE_AND_LAYOUT_SEPARATOR); + public static InputMethodSubtype[] createAdditionalSubtypesArray(String prefSubtypes) { + final String[] prefSubtypeArray = prefSubtypes.split(PREF_SUBTYPE_SEPARATOR); + final InputMethodSubtype[] subtypesArray = new InputMethodSubtype[prefSubtypeArray.length]; + for (int i = 0; i < prefSubtypeArray.length; i++) { + final String prefSubtype = prefSubtypeArray[i]; + final String elems[] = prefSubtype.split(LOCALE_AND_LAYOUT_SEPARATOR); + if (elems.length < 2 || elems.length > 3) { + throw new RuntimeException("Unknown subtype found in preference: " + prefSubtype); + } final String localeString = elems[0]; final String keyboardLayoutSetName = elems[1]; + final String extraValue = (elems.length == 3) ? elems[2] : null; subtypesArray[i] = AdditionalSubtype.createAdditionalSubtype( - localeString, keyboardLayoutSetName); + localeString, keyboardLayoutSetName, extraValue); } return subtypesArray; } diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java index a6ce04069..9c32f947c 100644 --- a/java/src/com/android/inputmethod/latin/InputAttributes.java +++ b/java/src/com/android/inputmethod/latin/InputAttributes.java @@ -162,4 +162,12 @@ public class InputAttributes { + "\n mIsSettingsSuggestionStripOn = " + mIsSettingsSuggestionStripOn + "\n mApplicationSpecifiedCompletionOn = " + mApplicationSpecifiedCompletionOn; } + + public static boolean inPrivateImeOptions(String packageName, String key, + EditorInfo editorInfo) { + if (editorInfo == null) return false; + final String findingKey = (packageName != null) ? packageName + "." + key + : key; + return StringUtils.containsInCsv(findingKey, editorInfo.privateImeOptions); + } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 682901cbc..9cfde8b77 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -669,12 +669,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.latinIME_onStartInputViewInternal(editorInfo); } - if (StringUtils.inPrivateImeOptions(null, IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo)) { + if (InputAttributes.inPrivateImeOptions( + null, IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo)) { Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions); Log.w(TAG, "Use " + getPackageName() + "." + IME_OPTION_NO_MICROPHONE + " instead"); } - if (StringUtils.inPrivateImeOptions(getPackageName(), IME_OPTION_FORCE_ASCII, editorInfo)) { + if (InputAttributes.inPrivateImeOptions( + getPackageName(), IME_OPTION_FORCE_ASCII, editorInfo)) { Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions); Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead"); @@ -1077,7 +1079,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (ic == null) return false; final CharSequence lastThree = ic.getTextBeforeCursor(3, 0); if (lastThree != null && lastThree.length() == 3 - && StringUtils.canBeFollowedByPeriod(lastThree.charAt(0)) + && canBeFollowedByPeriod(lastThree.charAt(0)) && lastThree.charAt(1) == Keyboard.CODE_SPACE && lastThree.charAt(2) == Keyboard.CODE_SPACE && mHandler.isAcceptingDoubleSpaces()) { @@ -1093,6 +1095,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return false; } + private static boolean canBeFollowedByPeriod(final int codePoint) { + // TODO: Check again whether there really ain't a better way to check this. + // TODO: This should probably be language-dependant... + return Character.isLetterOrDigit(codePoint) + || codePoint == Keyboard.CODE_SINGLE_QUOTE + || codePoint == Keyboard.CODE_DOUBLE_QUOTE + || codePoint == Keyboard.CODE_CLOSING_PARENTHESIS + || codePoint == Keyboard.CODE_CLOSING_SQUARE_BRACKET + || codePoint == Keyboard.CODE_CLOSING_CURLY_BRACKET + || codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET; + } + // "ic" may be null private static void removeTrailingSpaceWhileInBatchEdit(final InputConnection ic) { if (ic == null) return; diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index c160555f0..b83cec462 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -150,7 +150,7 @@ public class SettingsValues { mVoiceKeyOnMain = mVoiceMode != null && mVoiceMode.equals(voiceModeMain); mAdditionalSubtypes = AdditionalSubtype.createAdditionalSubtypesArray( - getCsvAdditionalSubtypes(prefs, res)); + getPrefAdditionalSubtypes(prefs, res)); } // Helper functions to create member values. @@ -315,10 +315,10 @@ public class SettingsValues { return mAdditionalSubtypes; } - public static String getCsvAdditionalSubtypes(final SharedPreferences prefs, + public static String getPrefAdditionalSubtypes(final SharedPreferences prefs, final Resources res) { - final String csvPredefinedSubtypes = res.getString(R.string.predefined_subtypes, ""); - return prefs.getString(Settings.PREF_CUSTOM_INPUT_STYLES, csvPredefinedSubtypes); + final String prefSubtypes = res.getString(R.string.predefined_subtypes, ""); + return prefs.getString(Settings.PREF_CUSTOM_INPUT_STYLES, prefSubtypes); } // Accessed from the settings interface, hence public diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index a599933d8..160581cbe 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -17,9 +17,6 @@ package com.android.inputmethod.latin; import android.text.TextUtils; -import android.view.inputmethod.EditorInfo; - -import com.android.inputmethod.keyboard.Keyboard; import java.util.ArrayList; import java.util.Locale; @@ -29,39 +26,38 @@ public class StringUtils { // This utility class is not publicly instantiable. } - public static boolean canBeFollowedByPeriod(final int codePoint) { - // TODO: Check again whether there really ain't a better way to check this. - // TODO: This should probably be language-dependant... - return Character.isLetterOrDigit(codePoint) - || codePoint == Keyboard.CODE_SINGLE_QUOTE - || codePoint == Keyboard.CODE_DOUBLE_QUOTE - || codePoint == Keyboard.CODE_CLOSING_PARENTHESIS - || codePoint == Keyboard.CODE_CLOSING_SQUARE_BRACKET - || codePoint == Keyboard.CODE_CLOSING_CURLY_BRACKET - || codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET; - } - public static int codePointCount(String text) { if (TextUtils.isEmpty(text)) return 0; return text.codePointCount(0, text.length()); } - private static boolean containsInCsv(String key, String csv) { - if (csv == null) - return false; - for (String option : csv.split(",")) { - if (option.equals(key)) - return true; + public static boolean containsInArray(String key, String[] array) { + for (final String element : array) { + if (key.equals(element)) return true; } return false; } - public static boolean inPrivateImeOptions(String packageName, String key, - EditorInfo editorInfo) { - if (editorInfo == null) - return false; - return containsInCsv(packageName != null ? packageName + "." + key : key, - editorInfo.privateImeOptions); + public static boolean containsInCsv(String key, String csv) { + if (TextUtils.isEmpty(csv)) return false; + return containsInArray(key, csv.split(",")); + } + + public static String appendToCsvIfNotExists(String key, String csv) { + if (TextUtils.isEmpty(csv)) return key; + if (containsInCsv(key, csv)) return csv; + return csv + "," + key; + } + + public static String removeFromCsvIfExists(String key, String csv) { + if (TextUtils.isEmpty(csv)) return ""; + final String[] elements = csv.split(","); + if (!containsInArray(key, elements)) return csv; + final ArrayList result = new ArrayList(elements.length - 1); + for (final String element : elements) { + if (!key.equals(element)) result.add(element); + } + return TextUtils.join(",", result); } /** diff --git a/tests/src/com/android/inputmethod/latin/StringUtilsTests.java b/tests/src/com/android/inputmethod/latin/StringUtilsTests.java new file mode 100644 index 000000000..8a5a82246 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/StringUtilsTests.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2012 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 com.android.inputmethod.latin; + +import android.test.AndroidTestCase; + +public class StringUtilsTests extends AndroidTestCase { + public void testContainsInArray() { + assertFalse("empty array", StringUtils.containsInArray("key", new String[0])); + assertFalse("not in 1 element", StringUtils.containsInArray("key", new String[] { + "key1" + })); + assertFalse("not in 2 elements", StringUtils.containsInArray("key", new String[] { + "key1", "key2" + })); + + assertTrue("in 1 element", StringUtils.containsInArray("key", new String[] { + "key" + })); + assertTrue("in 2 elements", StringUtils.containsInArray("key", new String[] { + "key1", "key" + })); + } + + public void testContainsInCsv() { + assertFalse("null", StringUtils.containsInCsv("key", null)); + assertFalse("empty", StringUtils.containsInCsv("key", "")); + assertFalse("not in 1 element", StringUtils.containsInCsv("key", "key1")); + assertFalse("not in 2 elements", StringUtils.containsInCsv("key", "key1,key2")); + + assertTrue("in 1 element", StringUtils.containsInCsv("key", "key")); + assertTrue("in 2 elements", StringUtils.containsInCsv("key", "key1,key")); + } + + public void testAppendToCsvIfNotExists() { + assertEquals("null", "key", StringUtils.appendToCsvIfNotExists("key", null)); + assertEquals("empty", "key", StringUtils.appendToCsvIfNotExists("key", "")); + + assertEquals("not in 1 element", "key1,key", + StringUtils.appendToCsvIfNotExists("key", "key1")); + assertEquals("not in 2 elements", "key1,key2,key", + StringUtils.appendToCsvIfNotExists("key", "key1,key2")); + + assertEquals("in 1 element", "key", + StringUtils.appendToCsvIfNotExists("key", "key")); + assertEquals("in 2 elements at position 1", "key,key2", + StringUtils.appendToCsvIfNotExists("key", "key,key2")); + assertEquals("in 2 elements at position 2", "key1,key", + StringUtils.appendToCsvIfNotExists("key", "key1,key")); + assertEquals("in 3 elements at position 2", "key1,key,key3", + StringUtils.appendToCsvIfNotExists("key", "key1,key,key3")); + } + + public void testRemoveFromCsvIfExists() { + assertEquals("null", "", StringUtils.removeFromCsvIfExists("key", null)); + assertEquals("empty", "", StringUtils.removeFromCsvIfExists("key", "")); + + assertEquals("not in 1 element", "key1", + StringUtils.removeFromCsvIfExists("key", "key1")); + assertEquals("not in 2 elements", "key1,key2", + StringUtils.removeFromCsvIfExists("key", "key1,key2")); + + assertEquals("in 1 element", "", + StringUtils.removeFromCsvIfExists("key", "key")); + assertEquals("in 2 elements at position 1", "key2", + StringUtils.removeFromCsvIfExists("key", "key,key2")); + assertEquals("in 2 elements at position 2", "key1", + StringUtils.removeFromCsvIfExists("key", "key1,key")); + assertEquals("in 3 elements at position 2", "key1,key3", + StringUtils.removeFromCsvIfExists("key", "key1,key,key3")); + + assertEquals("in 3 elements at position 1,2,3", "", + StringUtils.removeFromCsvIfExists("key", "key,key,key")); + assertEquals("in 5 elements at position 2,4", "key1,key3,key5", + StringUtils.removeFromCsvIfExists("key", "key1,key,key3,key,key5")); + } +} diff --git a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java index 12711c137..971fbc21b 100644 --- a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java +++ b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java @@ -165,13 +165,13 @@ public class SubtypeLocaleTests extends AndroidTestCase { public void testAdditionalSubtype() { final InputMethodSubtype DE_QWERTY = AdditionalSubtype.createAdditionalSubtype( - Locale.GERMAN.toString(), AdditionalSubtype.QWERTY); + Locale.GERMAN.toString(), AdditionalSubtype.QWERTY, null); final InputMethodSubtype FR_QWERTZ = AdditionalSubtype.createAdditionalSubtype( - Locale.FRENCH.toString(), AdditionalSubtype.QWERTZ); + Locale.FRENCH.toString(), AdditionalSubtype.QWERTZ, null); final InputMethodSubtype EN_AZERTY = AdditionalSubtype.createAdditionalSubtype( - Locale.ENGLISH.toString(), AdditionalSubtype.AZERTY); + Locale.ENGLISH.toString(), AdditionalSubtype.AZERTY, null); final InputMethodSubtype ZZ_AZERTY = AdditionalSubtype.createAdditionalSubtype( - SubtypeLocale.NO_LANGUAGE, AdditionalSubtype.AZERTY); + SubtypeLocale.NO_LANGUAGE, AdditionalSubtype.AZERTY, null); assertTrue(AdditionalSubtype.isAdditionalSubtype(FR_QWERTZ)); assertTrue(AdditionalSubtype.isAdditionalSubtype(DE_QWERTY)); -- cgit v1.2.3-83-g751a From 0806bb01d9e857db9fbac38b9b6e77feb9e9e4c9 Mon Sep 17 00:00:00 2001 From: Tom Ouyang Date: Thu, 19 Apr 2012 10:54:37 -0700 Subject: Binary bigram lookup checks both uppercase and lowercase when previous word is uppercase. Bug: 6363029 Change-Id: I71a1ed5b88f54fcc15bfaf89d3645b8f17ebb821 --- .../com/android/inputmethod/latin/StringUtils.java | 17 +++++++++++ .../src/com/android/inputmethod/latin/Suggest.java | 34 +++++++++++++--------- .../inputmethod/latin/StringUtilsTests.java | 11 +++++++ 3 files changed, 48 insertions(+), 14 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/StringUtils.java') diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index 160581cbe..a43b90525 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -122,6 +122,23 @@ public class StringUtils { return true; } + /** + * Returns true if cs contains any upper case characters. + * + * @param cs the CharSequence to check + * @return {@code true} if cs contains any upper case characters, {@code false} otherwise. + */ + public static boolean hasUpperCase(final CharSequence cs) { + final int length = cs.length(); + for (int i = 0, cp = 0; i < length; i += Character.charCount(cp)) { + cp = Character.codePointAt(cs, i); + if (Character.isUpperCase(cp)) { + return true; + } + } + return false; + } + /** * Remove duplicates from an array of strings. * diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 86753e2cc..7cbee4f71 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -242,13 +242,8 @@ public class Suggest implements Dictionary.WordCallback { mBigramSuggestions = new ArrayList(PREF_MAX_BIGRAMS); - CharSequence lowerPrevWord = prevWordForBigram.toString().toLowerCase(); - if (mMainDict != null && mMainDict.isValidWord(lowerPrevWord)) { - prevWordForBigram = lowerPrevWord; - } - for (final Dictionary dictionary : mBigramDictionaries.values()) { - dictionary.getBigrams(sEmptyWordComposer, prevWordForBigram, this); - } + getAllBigrams(prevWordForBigram, sEmptyWordComposer); + // Nothing entered: return all bigrams for the previous word int insertCount = Math.min(mBigramSuggestions.size(), mPrefMaxSuggestions); for (int i = 0; i < insertCount; ++i) { @@ -290,13 +285,7 @@ public class Suggest implements Dictionary.WordCallback { mBigramSuggestions = new ArrayList(PREF_MAX_BIGRAMS); if (!TextUtils.isEmpty(prevWordForBigram)) { - CharSequence lowerPrevWord = prevWordForBigram.toString().toLowerCase(); - if (mMainDict != null && mMainDict.isValidWord(lowerPrevWord)) { - prevWordForBigram = lowerPrevWord; - } - for (final Dictionary dictionary : mBigramDictionaries.values()) { - dictionary.getBigrams(wordComposer, prevWordForBigram, this); - } + getAllBigrams(prevWordForBigram, wordComposer); if (TextUtils.isEmpty(consideredWord)) { // Nothing entered: return all bigrams for the previous word int insertCount = Math.min(mBigramSuggestions.size(), mPrefMaxSuggestions); @@ -409,6 +398,23 @@ public class Suggest implements Dictionary.WordCallback { false /* isObsoleteSuggestions */); } + /** + * Adds all bigram predictions for prevWord. Also checks the lower case version of prevWord if + * it contains any upper case characters. + */ + private void getAllBigrams(final CharSequence prevWord, final WordComposer wordComposer) { + if (StringUtils.hasUpperCase(prevWord)) { + // TODO: Must pay attention to locale when changing case. + final CharSequence lowerPrevWord = prevWord.toString().toLowerCase(); + for (final Dictionary dictionary : mBigramDictionaries.values()) { + dictionary.getBigrams(wordComposer, lowerPrevWord, this); + } + } + for (final Dictionary dictionary : mBigramDictionaries.values()) { + dictionary.getBigrams(wordComposer, prevWord, this); + } + } + private static ArrayList getSuggestionsInfoListWithDebugInfo( final String typedWord, final ArrayList suggestions) { final SuggestedWordInfo typedWordInfo = suggestions.get(0); diff --git a/tests/src/com/android/inputmethod/latin/StringUtilsTests.java b/tests/src/com/android/inputmethod/latin/StringUtilsTests.java index 8a5a82246..5db06ef51 100644 --- a/tests/src/com/android/inputmethod/latin/StringUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/StringUtilsTests.java @@ -88,4 +88,15 @@ public class StringUtilsTests extends AndroidTestCase { assertEquals("in 5 elements at position 2,4", "key1,key3,key5", StringUtils.removeFromCsvIfExists("key", "key1,key,key3,key,key5")); } + + public void testHasUpperCase() { + assertTrue("single upper-case string", StringUtils.hasUpperCase("String")); + assertTrue("multi upper-case string", StringUtils.hasUpperCase("stRInG")); + assertTrue("all upper-case string", StringUtils.hasUpperCase("STRING")); + assertTrue("upper-case string with non-letters", StringUtils.hasUpperCase("He's")); + + assertFalse("empty string", StringUtils.hasUpperCase("")); + assertFalse("lower-case string", StringUtils.hasUpperCase("string")); + assertFalse("lower-case string with non-letters", StringUtils.hasUpperCase("he's")); + } } -- cgit v1.2.3-83-g751a From 01106f6a10ef2c6c8a338cb256e0799f7aca853b Mon Sep 17 00:00:00 2001 From: Kurt Partridge Date: Mon, 25 Jun 2012 11:17:48 -0700 Subject: fix IllegalOutOfBoundsException StringUtils.toCodePointArray() had thrown IllegalOutOfBoundsException if passed an empty string. change to just return an empty int[]. Bug: 6188932 Change-Id: Ic41c628c0d407f49fc98cd48cb7ea13d8d5bdd77 --- java/src/com/android/inputmethod/latin/StringUtils.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'java/src/com/android/inputmethod/latin/StringUtils.java') diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index a43b90525..6e7d985d6 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -184,6 +184,9 @@ public class StringUtils { final char[] characters = string.toCharArray(); final int length = characters.length; final int[] codePoints = new int[Character.codePointCount(characters, 0, length)]; + if (length <= 0) { + return new int[0]; + } int codePoint = Character.codePointAt(characters, 0); int dsti = 0; for (int srci = Character.charCount(codePoint); -- cgit v1.2.3-83-g751a