From 12e07767a1c3120c3d9c6718c7959ba0fe074a99 Mon Sep 17 00:00:00 2001 From: satok Date: Tue, 26 Apr 2011 12:02:37 +0900 Subject: Fix getMiddleDisplayLanguage Change-Id: Ia73d74b122069197ac471879e5f1cee34f31b182 --- java/src/com/android/inputmethod/latin/SubtypeSwitcher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index 158977927..1925e83ed 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -608,7 +608,7 @@ public class SubtypeSwitcher { } public static String getMiddleDisplayLanguage(Locale locale) { - return toTitleCase(locale.getDisplayLanguage(new Locale(locale.getLanguage()))); + return toTitleCase((new Locale(locale.getLanguage()).getDisplayLanguage(locale))); } public static String getShortDisplayLanguage(Locale locale) { -- cgit v1.2.3-83-g751a From 4556de4b4540b18d059759c88cd8254ae6a42fa7 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 26 Apr 2011 14:08:16 +0900 Subject: Do not use contacts for bigram prediction. bug: 4346034 Change-Id: Ibc3c27ca92ed61f1f689df3e90e2eb60fa0cbd33 --- java/src/com/android/inputmethod/latin/ContactsDictionary.java | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/ContactsDictionary.java b/java/src/com/android/inputmethod/latin/ContactsDictionary.java index 048f72dc5..bdb68cac7 100644 --- a/java/src/com/android/inputmethod/latin/ContactsDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsDictionary.java @@ -95,6 +95,14 @@ public class ContactsDictionary extends ExpandableDictionary { mLastLoadedContacts = SystemClock.uptimeMillis(); } + @Override + public void getBigrams(final WordComposer codes, final CharSequence previousWord, + final WordCallback callback) { + // Do not return bigrams from Contacts when nothing was typed. + if (codes.size() <= 0) return; + super.getBigrams(codes, previousWord, callback); + } + private void addWords(Cursor cursor) { clearDictionary(); -- cgit v1.2.3-83-g751a From 0c8d5ca023d54b7c9ef6c20eb7988288132bacb5 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 26 Apr 2011 16:28:56 +0900 Subject: Fix Eclipse warnings. This change is only there to fix warning issued by Eclipse. It should have absolutely no impact on the program logic. Change-Id: Ie0e242ac6c167297d33de19902340b0f6ecae9e1 --- .../inputmethod/compat/InputMethodManagerCompatWrapper.java | 6 +++--- java/src/com/android/inputmethod/deprecated/VoiceProxy.java | 12 ++++++------ .../deprecated/languageswitcher/LanguageSwitcher.java | 5 +---- .../inputmethod/deprecated/voice/VoiceInputLogger.java | 1 - java/src/com/android/inputmethod/latin/BinaryDictionary.java | 2 +- .../android/inputmethod/latin/BinaryDictionaryGetter.java | 3 --- java/src/com/android/inputmethod/latin/Dictionary.java | 2 +- java/src/com/android/inputmethod/latin/EditingUtils.java | 2 +- java/src/com/android/inputmethod/latin/Suggest.java | 2 +- java/src/com/android/inputmethod/latin/Utils.java | 2 +- 10 files changed, 15 insertions(+), 22 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java index d99f40765..1cc13f249 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java @@ -118,7 +118,7 @@ public class InputMethodManagerCompatWrapper { } Object retval = CompatUtils.invoke(mImm, null, METHOD_getEnabledInputMethodSubtypeList, (imi != null ? imi.getInputMethodInfo() : null), allowsImplicitlySelectedSubtypes); - if (retval == null || !(retval instanceof List) || ((List)retval).isEmpty()) { + if (retval == null || !(retval instanceof List) || ((List)retval).isEmpty()) { if (!FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES) { // Returns an empty list return Collections.emptyList(); @@ -137,7 +137,7 @@ public class InputMethodManagerCompatWrapper { } return subtypeList; } - return CompatUtils.copyInputMethodSubtypeListToWrapper((List)retval); + return CompatUtils.copyInputMethodSubtypeListToWrapper(retval); } private InputMethodInfoCompatWrapper getLatinImeInputMethodInfo() { @@ -159,7 +159,7 @@ public class InputMethodManagerCompatWrapper { public Map> getShortcutInputMethodsAndSubtypes() { Object retval = CompatUtils.invoke(mImm, null, METHOD_getShortcutInputMethodsAndSubtypes); - if (retval == null || !(retval instanceof Map) || ((Map)retval).isEmpty()) { + if (retval == null || !(retval instanceof Map) || ((Map)retval).isEmpty()) { if (!FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES) { // Returns an empty map return Collections.emptyMap(); diff --git a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java index 0d0591bd0..753dceead 100644 --- a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java +++ b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java @@ -754,15 +754,15 @@ public class VoiceProxy implements VoiceInput.UiListener { } public static class VoiceLoggerWrapper { - private static final VoiceLoggerWrapper sInstance = new VoiceLoggerWrapper(); + private static final VoiceLoggerWrapper sLoggerWrapperInstance = new VoiceLoggerWrapper(); private VoiceInputLogger mLogger; public static VoiceLoggerWrapper getInstance(Context context) { - if (sInstance.mLogger == null) { + if (sLoggerWrapperInstance.mLogger == null) { // Not thread safe, but it's ok. - sInstance.mLogger = VoiceInputLogger.getLogger(context); + sLoggerWrapperInstance.mLogger = VoiceInputLogger.getLogger(context); } - return sInstance; + return sLoggerWrapperInstance; } // private for the singleton @@ -795,10 +795,10 @@ public class VoiceProxy implements VoiceInput.UiListener { } public static class VoiceInputWrapper { - private static final VoiceInputWrapper sInstance = new VoiceInputWrapper(); + private static final VoiceInputWrapper sInputWrapperInstance = new VoiceInputWrapper(); private VoiceInput mVoiceInput; public static VoiceInputWrapper getInstance() { - return sInstance; + return sInputWrapperInstance; } public void setVoiceInput(VoiceInput voiceInput, SubtypeSwitcher switcher) { if (mVoiceInput == null && voiceInput != null) { diff --git a/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java b/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java index 1a606eaaf..5ef236e31 100644 --- a/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java +++ b/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java @@ -16,7 +16,6 @@ package com.android.inputmethod.deprecated.languageswitcher; -import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.Settings; @@ -38,6 +37,7 @@ import java.util.Locale; public class LanguageSwitcher { private static final String TAG = LanguageSwitcher.class.getSimpleName(); + @SuppressWarnings("unused") private static final String KEYBOARD_MODE = "keyboard"; private static final String[] EMPTY_STIRNG_ARRAY = new String[0]; @@ -154,7 +154,6 @@ public class LanguageSwitcher { /** * Returns the currently selected input locale, or the display locale if no specific * locale was selected for input. - * @return */ public Locale getInputLocale() { if (getLocaleCount() == 0) return mDefaultInputLocale; @@ -175,7 +174,6 @@ public class LanguageSwitcher { /** * Returns the next input locale in the list. Wraps around to the beginning of the * list if we're at the end of the list. - * @return */ public Locale getNextInputLocale() { if (getLocaleCount() == 0) return mDefaultInputLocale; @@ -201,7 +199,6 @@ public class LanguageSwitcher { /** * Returns the previous input locale in the list. Wraps around to the end of the * list if we're at the beginning of the list. - * @return */ public Locale getPrevInputLocale() { if (getLocaleCount() == 0) return mDefaultInputLocale; diff --git a/java/src/com/android/inputmethod/deprecated/voice/VoiceInputLogger.java b/java/src/com/android/inputmethod/deprecated/voice/VoiceInputLogger.java index dcd124f70..87b943426 100644 --- a/java/src/com/android/inputmethod/deprecated/voice/VoiceInputLogger.java +++ b/java/src/com/android/inputmethod/deprecated/voice/VoiceInputLogger.java @@ -17,7 +17,6 @@ package com.android.inputmethod.deprecated.voice; import com.android.common.speech.LoggingEvents; -import com.android.common.userhappiness.UserHappinessSignals; import com.android.inputmethod.deprecated.compat.VoiceInputLoggerCompatUtils; import android.content.Context; diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 7e63aacdf..5416cd571 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -145,7 +145,7 @@ public class BinaryDictionary extends Dictionary { * @param context application context for reading resources * @param dicTypeId the type of the dictionary being created, out of the list in Suggest.DIC_* * @param locale the locale for which to create the dictionary - * @param fallBackResId the id of the resource to use as a fallback if no pack is found + * @param fallbackResId the id of the resource to use as a fallback if no pack is found * @return an initialized instance of BinaryDictionary */ public static BinaryDictionary initDictionaryFromManager(Context context, int dicTypeId, diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java index 72512c7e1..c4e098a0c 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java @@ -65,9 +65,6 @@ class BinaryDictionaryGetter { * If that fails: * - Returns null. * @return The address of a valid file, or null. - * @throws FileNotFoundException if a dictionary provider returned a file name, but the - * file cannot be found. - * @throws IOException if there was an I/O problem reading or copying a file. */ public static AssetFileAddress getDictionaryFile(Locale locale, Context context, int fallbackResId) { diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index ac43d6477..c7737b9a2 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -61,7 +61,7 @@ public abstract class Dictionary { * words are added through the callback object. * @param composer the key sequence to match * @param callback the callback object to send matched words to as possible candidates - * @see WordCallback#addWord(char[], int, int) + * @see WordCallback#addWord(char[], int, int, int, int, DataType) */ abstract public void getWords(final WordComposer composer, final WordCallback callback); diff --git a/java/src/com/android/inputmethod/latin/EditingUtils.java b/java/src/com/android/inputmethod/latin/EditingUtils.java index ea281f5b8..39e7e402f 100644 --- a/java/src/com/android/inputmethod/latin/EditingUtils.java +++ b/java/src/com/android/inputmethod/latin/EditingUtils.java @@ -73,7 +73,7 @@ public class EditingUtils { /** * @param connection connection to the current text field. - * @param sep characters which may separate words + * @param separators characters which may separate words * @return the word that surrounds the cursor, including up to one trailing * separator. For example, if the field contains "he|llo world", where | * represents the cursor, then "hello " will be returned. diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 15743ee2d..1f6146a6d 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -56,7 +56,7 @@ public class Suggest implements Dictionary.WordCallback { /** * Maximum possible bigram frequency. Will depend on how many bits are being used in data - * structure. Maximum bigram freqeuncy will get the BIGRAM_MULTIPLIER_MAX as the multiplier. + * structure. Maximum bigram frequency will get the BIGRAM_MULTIPLIER_MAX as the multiplier. */ public static final int MAXIMUM_BIGRAM_FREQUENCY = 127; diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index f8b23cb65..b5afb5079 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -648,6 +648,6 @@ public class Utils { /** Convert pixel to DIP */ public static int dipToPixel(float scale, int dip) { - return (int) ((float) dip * scale + 0.5); + return (int) (dip * scale + 0.5); } } -- cgit v1.2.3-83-g751a From a7a659ab0f9e9667bf6c6e2d7d07ff2857ae8b13 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Tue, 26 Apr 2011 20:10:54 +0900 Subject: Shorter timeout to update auto caps state (100ms) Bug: 4319726 Change-Id: I068279ddfbb79dfebb6ab845d97cccd62d9e052a --- java/src/com/android/inputmethod/latin/LatinIME.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 28fd6aad7..751304b73 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -112,7 +112,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private static final int DELAY_UPDATE_SUGGESTIONS = 180; private static final int DELAY_UPDATE_OLD_SUGGESTIONS = 300; - private static final int DELAY_UPDATE_SHIFT_STATE = 300; + private static final int DELAY_UPDATE_SHIFT_STATE = 100; private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100; // How many continuous deletes at which to start deleting at a higher speed. -- cgit v1.2.3-83-g751a From b2e5e5937ca96a448081466a9f43e937787f0c24 Mon Sep 17 00:00:00 2001 From: satok Date: Tue, 26 Apr 2011 14:50:54 +0900 Subject: Handle overflow properly in multiplyRate Bug: 3401513 Change-Id: I8dd2523caa58bb51c378a01e160a58f9106ce9b8 --- java/src/com/android/inputmethod/latin/Utils.java | 6 ++- native/src/unigram_dictionary.cpp | 61 ++++++++++++++++------- 2 files changed, 48 insertions(+), 19 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index f8b23cb65..b537b9f8f 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -48,6 +48,7 @@ public class Utils { private static final String TAG = Utils.class.getSimpleName(); private static final int MINIMUM_SAFETY_NET_CHAR_LENGTH = 4; private static boolean DBG = LatinImeLogger.sDBG; + private static boolean DBG_EDIT_DISTANCE = false; private Utils() { // Intentional empty constructor for utility class. @@ -289,7 +290,7 @@ public class Utils { } } } - if (LatinImeLogger.sDBG) { + if (DBG_EDIT_DISTANCE) { Log.d(TAG, "editDistance:" + s + "," + t); for (int i = 0; i < dp.length; ++i) { StringBuffer sb = new StringBuffer(); @@ -338,6 +339,7 @@ public class Utils { private static final int MAX_INITIAL_SCORE = 255; private static final int TYPED_LETTER_MULTIPLIER = 2; private static final int FULL_WORD_MULTIPLIER = 2; + private static final int S_INT_MAX = 2147483647; public static double calcNormalizedScore(CharSequence before, CharSequence after, int score) { final int beforeLength = before.length(); final int afterLength = after.length(); @@ -352,7 +354,7 @@ public class Utils { } } if (spaceCount == afterLength) return 0; - final double maximumScore = MAX_INITIAL_SCORE + final double maximumScore = score == S_INT_MAX ? S_INT_MAX : MAX_INITIAL_SCORE * Math.pow( TYPED_LETTER_MULTIPLIER, Math.min(beforeLength, afterLength - spaceCount)) * FULL_WORD_MULTIPLIER; diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp index b9f4b961d..cd2f141cf 100644 --- a/native/src/unigram_dictionary.cpp +++ b/native/src/unigram_dictionary.cpp @@ -300,7 +300,7 @@ bool UnigramDictionary::addWord(unsigned short *word, int length, int frequency) if (DEBUG_DICT) { char s[length + 1]; for (int i = 0; i <= length; i++) s[i] = word[i]; - LOGI("Added word = %s, freq = %d", s, frequency); + LOGI("Added word = %s, freq = %d, %d", s, frequency, S_INT_MAX); } memmove((char*) mFrequencies + (insertAt + 1) * sizeof(mFrequencies[0]), (char*) mFrequencies + insertAt * sizeof(mFrequencies[0]), @@ -409,11 +409,44 @@ void UnigramDictionary::getSuggestionCandidates(const int skipPos, } } -inline static void multiplyRate(const int rate, int *freq) { - if (rate > 1000000) { - *freq = (*freq / 100) * rate; +static const int TWO_31ST_DIV_255 = S_INT_MAX / 255; +static inline int capped255MultForFullMatchAccentsOrCapitalizationDifference(const int num) { + return (num < TWO_31ST_DIV_255 ? 255 * num : S_INT_MAX); +} + +static const int TWO_31ST_DIV_2 = S_INT_MAX / 2; +inline static void multiplyIntCapped(const int multiplier, int *base) { + const int temp = *base; + if (temp != S_INT_MAX) { + // Branch if multiplier == 2 for the optimization + if (multiplier == 2) { + *base = TWO_31ST_DIV_2 >= temp ? temp << 1 : S_INT_MAX; + } else { + const int tempRetval = temp * multiplier; + *base = tempRetval >= temp ? tempRetval : S_INT_MAX; + } + } +} + +inline static int powerIntCapped(const int base, const int n) { + if (false && base == 2) { + return n < 31 ? 1 << n : S_INT_MAX; } else { - *freq = *freq * rate / 100; + int ret = base; + for (int i = 1; i < n; ++i) multiplyIntCapped(base, &ret); + return ret; + } +} + +inline static void multiplyRate(const int rate, int *freq) { + if (*freq != S_INT_MAX) { + if (*freq > 1000000) { + *freq /= 100; + multiplyIntCapped(rate, freq); + } else { + multiplyIntCapped(rate, freq); + *freq /= 100; + } } } @@ -449,9 +482,7 @@ inline static int calcFreqForSplitTwoWords( // (firstFreq * (1 - 1 / (firstWordLength + 1)) + secondFreq * (1 - 1 / (secondWordLength + 1))) // * (1 - 1 / totalLength) / (1 - 1 / (totalLength + 1)) - for (int i = 0; i < totalLength; ++i) { - totalFreq *= typedLetterMultiplier; - } + multiplyIntCapped(powerIntCapped(typedLetterMultiplier, totalLength), &totalFreq); // This is another workaround to offset the demotion which will be done in // calcNormalizedScore in Utils.java. @@ -499,7 +530,7 @@ bool UnigramDictionary::getSplitTwoWordsSuggestion(const int inputLength, int pairFreq = calcFreqForSplitTwoWords( TYPED_LETTER_MULTIPLIER, firstWordLength, secondWordLength, firstFreq, secondFreq); if (DEBUG_DICT) { - LOGI("Missing space: %d, %d, %d, %d, %d", firstFreq, secondFreq, pairFreq, inputLength, + LOGI("Split two words: %d, %d, %d, %d, %d", firstFreq, secondFreq, pairFreq, inputLength, TYPED_LETTER_MULTIPLIER); } addWord(word, newWordLength, pairFreq); @@ -559,10 +590,6 @@ void UnigramDictionary::getWordsRec(const int childrenCount, const int pos, cons } } -static const int TWO_31ST_DIV_255 = S_INT_MAX / 255; -static inline int capped255MultForFullMatchAccentsOrCapitalizationDifference(const int num) { - return (num < TWO_31ST_DIV_255 ? 255 * num : S_INT_MAX); -} inline int UnigramDictionary::calculateFinalFreq(const int inputIndex, const int depth, const int matchWeight, const int skipPos, const int excessivePos, const int transposedPos, const int freq, const bool sameLength) const { @@ -591,7 +618,7 @@ inline int UnigramDictionary::calculateFinalFreq(const int inputIndex, const int } } int lengthFreq = TYPED_LETTER_MULTIPLIER; - for (int i = 0; i < depth; ++i) lengthFreq *= TYPED_LETTER_MULTIPLIER; + multiplyIntCapped(powerIntCapped(TYPED_LETTER_MULTIPLIER, depth), &lengthFreq); if (lengthFreq == matchWeight) { // Full exact match if (depth > 1) { @@ -608,13 +635,13 @@ inline int UnigramDictionary::calculateFinalFreq(const int inputIndex, const int if (DEBUG_DICT) { LOGI("Found one proximity correction."); } - finalFreq *= 2; + multiplyIntCapped(TYPED_LETTER_MULTIPLIER, &finalFreq); multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq); } if (DEBUG_DICT) { LOGI("calc: %d, %d", depth, sameLength); } - if (sameLength) finalFreq *= FULL_WORD_MULTIPLIER; + if (sameLength) multiplyIntCapped(FULL_WORD_MULTIPLIER, &finalFreq); return finalFreq; } @@ -767,7 +794,7 @@ inline bool UnigramDictionary::processCurrentNode(const int pos, const int depth // If inputIndex is greater than mInputLength, that means there is no // proximity chars. So, we don't need to check proximity. if (SAME_OR_ACCENTED_OR_CAPITALIZED_CHAR == matchedProximityCharId) { - matchWeight = matchWeight * TYPED_LETTER_MULTIPLIER; + multiplyIntCapped(TYPED_LETTER_MULTIPLIER, &matchWeight); } bool isSameAsUserTypedLength = mInputLength == inputIndex + 1 || (excessivePos == mInputLength - 1 && inputIndex == mInputLength - 2); -- cgit v1.2.3-83-g751a From 717cef79ead5d63a01d09b47caab0a3d719c69df Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Tue, 26 Apr 2011 14:27:35 +0900 Subject: Fix quotation marks This change * Allows snap back from symbols shifted to symbol layout. * Add "left single", "right single", "single low" and "single high reversed" quotation marks to popup characters of "single quote". * Add "double low" and "double high reversed" quatation marks to popup characters of "double quote". * Add "prime" and "double prime" to popup characters of "degree". * Disable non-ASCII key of symbol more layout on passowrd input. Bug: 4345054 Bug: 4347045 Change-Id: I8168ce6a74a9536e4966f7f9d1099ac0132925c7 --- java/res/xml-xlarge/kbd_symbols.xml | 3 +- java/res/xml-xlarge/kbd_symbols_shift.xml | 3 +- java/res/xml/kbd_key_styles.xml | 23 ++++ java/res/xml/kbd_symbols.xml | 6 +- java/res/xml/kbd_symbols_shift.xml | 16 ++- java/res/xml/kbd_symbols_shift_row4.xml | 10 +- .../inputmethod/keyboard/KeyboardSwitcher.java | 127 +++++++++++++++------ .../inputmethod/keyboard/PointerTracker.java | 2 +- 8 files changed, 146 insertions(+), 44 deletions(-) (limited to 'java/src') diff --git a/java/res/xml-xlarge/kbd_symbols.xml b/java/res/xml-xlarge/kbd_symbols.xml index 1061178e0..f1deae0f9 100644 --- a/java/res/xml-xlarge/kbd_symbols.xml +++ b/java/res/xml-xlarge/kbd_symbols.xml @@ -211,9 +211,10 @@ latin:keyLabel="-" /> + + latin:popupCharacters="“,”,„,‟,«,»,‘,’,‚,‛" /> diff --git a/java/res/xml-xlarge/kbd_symbols_shift.xml b/java/res/xml-xlarge/kbd_symbols_shift.xml index 8359b7571..cc23358a5 100644 --- a/java/res/xml-xlarge/kbd_symbols_shift.xml +++ b/java/res/xml-xlarge/kbd_symbols_shift.xml @@ -99,7 +99,8 @@ latin:popupCharacters="↑,↓,←,→" /> + latin:keyLabel="°" + latin:popupCharacters="′,″" /> + + + + + + + + + + + \ No newline at end of file diff --git a/java/res/xml/kbd_symbols.xml b/java/res/xml/kbd_symbols.xml index 0b8b89969..9748bce8b 100644 --- a/java/res/xml/kbd_symbols.xml +++ b/java/res/xml/kbd_symbols.xml @@ -105,12 +105,14 @@ + + latin:popupCharacters="“,”,„,‟,«,»" + latin:maxPopupKeyboardColumn="6" /> + latin:popupCharacters="‘,’,‚,‛,´" /> @@ -64,13 +69,18 @@ latin:keyStyle="nonSpecialBackgroundTabKeyStyle" latin:keyEdgeFlags="left" /> + latin:keyStyle="nonPasswordSymbolKeyStyle" + latin:keyLabel="°" + latin:popupCharacters="′,″" /> @@ -92,12 +102,16 @@ latin:visualInsetsRight="1%p" latin:keyEdgeFlags="left" /> + latin:popupCharacters="“,”,„,‟,«,»,‘,’,‚,‛" + latin:keyStyle="nonPasswordFunctionalKeyStyle" /> + latin:keyStyle="nonPasswordFunctionalKeyStyle" /> + latin:popupCharacters="“,”,„,‟,«,»,‘,’,‚,‛" + latin:keyStyle="nonPasswordFunctionalKeyStyle" /> + latin:keyStyle="nonPasswordFunctionalKeyStyle" /> = '\u2018' && c <= '\u201f') + return true; + // \u00ab: Left-pointing double angle quotation mark + // \u00bb: Right-pointing double angle quotation mark + if (c == '\u00ab' || c == '\u00bb') + return true; + return false; + } + /** * Updates state machine to figure out when to automatically snap back to the previous mode. */ - public void onKey(int key) { + public void onKey(int code) { if (DEBUG_STATE) - Log.d(TAG, "onKey: code=" + key + " autoModeSwitchState=" + mAutoModeSwitchState + Log.d(TAG, "onKey: code=" + code + " switchState=" + mSwitchState + " pointers=" + getPointerCount()); - switch (mAutoModeSwitchState) { - case AUTO_MODE_SWITCH_STATE_MOMENTARY: + switch (mSwitchState) { + case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL: // Only distinct multi touch devices can be in this state. // On non-distinct multi touch devices, mode change key is handled by // {@link LatinIME#onCodeInput}, not by {@link LatinIME#onPress} and - // {@link LatinIME#onRelease}. So, on such devices, {@link #mAutoModeSwitchState} starts - // from {@link #AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN}, or - // {@link #AUTO_MODE_SWITCH_STATE_ALPHA}, not from - // {@link #AUTO_MODE_SWITCH_STATE_MOMENTARY}. - if (key == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { + // {@link LatinIME#onRelease}. So, on such devices, {@link #mSwitchState} starts + // from {@link #SWITCH_STATE_SYMBOL_BEGIN}, or {@link #SWITCH_STATE_ALPHA}, not from + // {@link #SWITCH_STATE_MOMENTARY}. + if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { // Detected only the mode change key has been pressed, and then released. if (mIsSymbols) { - mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN; + mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; } else { - mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; + mSwitchState = SWITCH_STATE_ALPHA; } } else if (getPointerCount() == 1) { // Snap back to the previous keyboard mode if the user pressed the mode change key @@ -628,18 +671,34 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } else { // Chording input is being started. The keyboard mode will be snapped back to the // previous mode in {@link onReleaseSymbol} when the mode change key is released. - mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_CHORDING; + mSwitchState = SWITCH_STATE_CHORDING_ALPHA; + } + break; + case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE: + if (code == Keyboard.CODE_SHIFT) { + // Detected only the shift key has been pressed on symbol layout, and then released. + mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; + } else if (getPointerCount() == 1) { + // Snap back to the previous keyboard mode if the user pressed the shift key on + // symbol mode and slid to other key, then released the finger. + toggleShift(); + mSwitchState = SWITCH_STATE_SYMBOL; + } else { + // Chording input is being started. The keyboard mode will be snapped back to the + // previous mode in {@link onReleaseShift} when the shift key is released. + mSwitchState = SWITCH_STATE_CHORDING_SYMBOL; } break; - case AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN: - if (key != Keyboard.CODE_SPACE && key != Keyboard.CODE_ENTER && key >= 0) { - mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL; + case SWITCH_STATE_SYMBOL_BEGIN: + if (!isSpaceCharacter(code) && code >= 0) { + mSwitchState = SWITCH_STATE_SYMBOL; } break; - case AUTO_MODE_SWITCH_STATE_SYMBOL: + case SWITCH_STATE_SYMBOL: + case SWITCH_STATE_CHORDING_SYMBOL: // Snap back to alpha keyboard mode if user types one or more non-space/enter - // characters followed by a space/enter. - if (key == Keyboard.CODE_ENTER || key == Keyboard.CODE_SPACE) { + // characters followed by a space/enter or quotation mark. + if (isSpaceCharacter(code) || isQuoteCharacter(code)) { changeKeyboardMode(); } break; diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index e3161f610..abd1ef286 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -662,7 +662,7 @@ public class PointerTracker { // We need not start long press timer on the key which has manual temporary upper case // code defined and the keyboard is in manual temporary upper case mode. return; - } else if (mKeyboardSwitcher.isInMomentaryAutoModeSwitchState()) { + } else if (mKeyboardSwitcher.isInMomentarySwitchState()) { // We use longer timeout for sliding finger input started from the symbols mode key. mHandler.startLongPressTimer(mLongPressKeyTimeout * 3, keyIndex, this); } else { -- cgit v1.2.3-83-g751a From e541f03286189eebbc4a75615070e0e6f43ec37c Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Tue, 26 Apr 2011 19:49:34 +0900 Subject: Release caps lock by double tap on shift key Bug: 3319295 Change-Id: Ie0cad06c7b1afac0f33af76128303517e9e7bddc --- .../inputmethod/keyboard/KeyboardSwitcher.java | 4 ++++ .../android/inputmethod/keyboard/KeyboardView.java | 24 +++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index e163457d8..5bf8aa8b3 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -486,6 +486,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } else if (isShiftLocked() && !shiftKeyState.isIgnoring() && !withSliding) { // Shift has been pressed without chording while caps lock state. toggleCapsLock(); + // To be able to turn off caps lock by "double tap" on shift key, we should ignore + // the second tap of the "double tap" from now for a while because we just have + // already turned off caps lock above. + mInputView.startIgnoringDoubleTap(); } else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted() && !withSliding) { // Shift has been pressed without chording while shifted state. diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index c36895258..b6f2cab01 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -44,6 +44,7 @@ import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.LinearLayout; @@ -189,6 +190,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { private static final int MSG_REPEAT_KEY = 3; private static final int MSG_LONGPRESS_KEY = 4; private static final int MSG_LONGPRESS_SHIFT_KEY = 5; + private static final int MSG_IGNORE_DOUBLE_TAP = 6; private boolean mInKeyRepeat; @@ -286,6 +288,16 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { public void cancelKeyTimers() { cancelKeyRepeatTimer(); cancelLongPressTimers(); + removeMessages(MSG_IGNORE_DOUBLE_TAP); + } + + public void startIgnoringDoubleTap() { + sendMessageDelayed(obtainMessage(MSG_IGNORE_DOUBLE_TAP), + ViewConfiguration.getDoubleTapTimeout()); + } + + public boolean isIgnoringDoubleTap() { + return hasMessages(MSG_IGNORE_DOUBLE_TAP); } public void cancelAllMessages() { @@ -449,7 +461,12 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { final PointerTracker tracker = getPointerTracker(id); // If the second down event is also on shift key. if (tracker.isOnShiftKey((int)secondDown.getX(), (int)secondDown.getY())) { - onDoubleTapShiftKey(tracker); + // Detected a double tap on shift key. If we are in the ignoring double tap + // mode, it means we have already turned off caps lock in + // {@link KeyboardSwitcher#onReleaseShift} . + final boolean ignoringDoubleTap = mHandler.isIgnoringDoubleTap(); + if (!ignoringDoubleTap) + onDoubleTapShiftKey(tracker); return true; } // Otherwise these events should not be handled as double tap. @@ -468,6 +485,11 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval); } + public void startIgnoringDoubleTap() { + if (ENABLE_CAPSLOCK_BY_DOUBLETAP) + mHandler.startIgnoringDoubleTap(); + } + public void setOnKeyboardActionListener(KeyboardActionListener listener) { mKeyboardActionListener = listener; for (PointerTracker tracker : mPointerTrackers) { -- cgit v1.2.3-83-g751a From 309bff562fbaf47488e6bf6636840f00574187d8 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 27 Apr 2011 15:43:03 +0900 Subject: Add a method to set the locale to Utils. Add a setLocale method to Utils that returns the previous locale. Also unify all calls through the code. Change-Id: Ic850dc5df19fba00ed3601835652859b4321b544 --- .../deprecated/languageswitcher/InputLanguageSelection.java | 9 ++------- .../com/android/inputmethod/keyboard/KeyboardSwitcher.java | 5 +++-- java/src/com/android/inputmethod/latin/LatinIME.java | 6 +++--- java/src/com/android/inputmethod/latin/SubtypeSwitcher.java | 13 ------------- java/src/com/android/inputmethod/latin/Utils.java | 10 ++++++++++ 5 files changed, 18 insertions(+), 25 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java index ce576d0cc..6678082b7 100644 --- a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java +++ b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java @@ -29,7 +29,6 @@ import org.xmlpull.v1.XmlPullParserException; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; -import android.content.res.Configuration; import android.content.res.Resources; import android.os.Bundle; import android.preference.CheckBoxPreference; @@ -123,10 +122,7 @@ public class InputLanguageSelection extends PreferenceActivity { private Pair hasDictionaryOrLayout(Locale locale) { if (locale == null) return new Pair(false, false); final Resources res = getResources(); - final Configuration conf = res.getConfiguration(); - final Locale saveLocale = conf.locale; - conf.locale = locale; - res.updateConfiguration(conf, res.getDisplayMetrics()); + final Locale saveLocale = Utils.setSystemLocale(res, locale); boolean hasDictionary = false; boolean hasLayout = false; @@ -155,8 +151,7 @@ public class InputLanguageSelection extends PreferenceActivity { } catch (XmlPullParserException e) { } catch (IOException e) { } - conf.locale = saveLocale; - res.updateConfiguration(conf, res.getDisplayMetrics()); + Utils.setSystemLocale(res, saveLocale); return new Pair(hasDictionary, hasLayout); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index e163457d8..8627508e5 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -164,7 +164,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha final SoftReference ref = mKeyboardCache.get(id); LatinKeyboard keyboard = (ref == null) ? null : ref.get(); if (keyboard == null) { - final Locale savedLocale = mSubtypeSwitcher.changeSystemLocale( + final Resources res = mInputMethodService.getResources(); + final Locale savedLocale = Utils.setSystemLocale(res, mSubtypeSwitcher.getInputLocale()); keyboard = new LatinKeyboard(mInputMethodService, id); @@ -178,7 +179,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": " + ((ref == null) ? "LOAD" : "GCed") + " id=" + id); - mSubtypeSwitcher.changeSystemLocale(savedLocale); + Utils.setSystemLocale(res, savedLocale); } else if (DEBUG) { Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": HIT id=" + id); } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 28fd6aad7..175467fcb 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -470,14 +470,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final String localeStr = mSubtypeSwitcher.getInputLocaleStr(); final Locale keyboardLocale = new Locale(localeStr); - final Locale savedLocale = mSubtypeSwitcher.changeSystemLocale(keyboardLocale); + final Resources res = mResources; + final Locale savedLocale = Utils.setSystemLocale(res, keyboardLocale); if (mSuggest != null) { mSuggest.close(); } final SharedPreferences prefs = mPrefs; mQuickFixes = isQuickFixesEnabled(prefs); - final Resources res = mResources; int mainDicResId = Utils.getMainDictionaryResourceId(res); mSuggest = new Suggest(this, mainDicResId, keyboardLocale); loadAndSetAutoCorrectionThreshold(prefs); @@ -499,7 +499,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mWordSeparators = res.getString(R.string.word_separators); mSentenceSeparators = res.getString(R.string.sentence_separators); - mSubtypeSwitcher.changeSystemLocale(savedLocale); + Utils.setSystemLocale(res, savedLocale); } /* package private */ void resetSuggestMainDict() { diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index 1925e83ed..d8012087b 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -475,19 +475,6 @@ public class SubtypeSwitcher { } } - /** - * Change system locale for this application - * @param newLocale - * @return oldLocale - */ - public Locale changeSystemLocale(Locale newLocale) { - Configuration conf = mResources.getConfiguration(); - Locale oldLocale = conf.locale; - conf.locale = newLocale; - mResources.updateConfiguration(conf, mResources.getDisplayMetrics()); - return oldLocale; - } - public boolean isKeyboardMode() { return KEYBOARD_MODE.equals(getCurrentSubtypeMode()); } diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index b5afb5079..9d7b98410 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -23,6 +23,7 @@ import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; import android.content.Context; +import android.content.res.Configuration; import android.content.res.Resources; import android.inputmethodservice.InputMethodService; import android.os.AsyncTask; @@ -43,6 +44,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Locale; public class Utils { private static final String TAG = Utils.class.getSimpleName(); @@ -650,4 +652,12 @@ public class Utils { public static int dipToPixel(float scale, int dip) { return (int) (dip * scale + 0.5); } + + public static Locale setSystemLocale(Resources res, Locale newLocale) { + final Configuration conf = res.getConfiguration(); + final Locale saveLocale = conf.locale; + conf.locale = newLocale; + res.updateConfiguration(conf, res.getDisplayMetrics()); + return saveLocale; + } } -- cgit v1.2.3-83-g751a From e4181036f68d6bcf8ef928075b954a65243b202a Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Wed, 27 Apr 2011 16:34:13 +0900 Subject: Enable long press caps lock Bug: 3319295 Change-Id: I413062c759a1d91c66fcbf5dd04050dfbf15094f --- java/src/com/android/inputmethod/keyboard/KeyboardView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index b6f2cab01..11476e069 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -74,7 +74,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { private static final boolean DEBUG_SHOW_ALIGN = false; private static final boolean DEBUG_KEYBOARD_GRID = false; - private static final boolean ENABLE_CAPSLOCK_BY_LONGPRESS = false; + private static final boolean ENABLE_CAPSLOCK_BY_LONGPRESS = true; private static final boolean ENABLE_CAPSLOCK_BY_DOUBLETAP = true; public static final int COLOR_SCHEME_WHITE = 0; -- cgit v1.2.3-83-g751a From 4250eb27f54f8fedc388fe4825b0646a88778744 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 26 Apr 2011 21:49:09 +0900 Subject: Create a dictionary collection and a dictionary factory. The dictionary collection is a class complying to the Dictionary interface that acts as a front end to a collection of arbitrarily many dictionaries of any type. The dictionary factory is a helper class for creating various dictionaries and get some meta information about them. At the same time, this change makes the BinaryDictionary class not a singleton any more. This also needs I9afe61a9 to not break the build. Change-Id: I61fdcc4867fcda18342807bf1865e6e46979e5d5 --- .../languageswitcher/InputLanguageSelection.java | 15 +- .../inputmethod/latin/BinaryDictionary.java | 112 +++------------ .../inputmethod/latin/DictionaryCollection.java | 66 +++++++++ .../inputmethod/latin/DictionaryFactory.java | 159 +++++++++++++++++++++ .../src/com/android/inputmethod/latin/Suggest.java | 18 ++- 5 files changed, 254 insertions(+), 116 deletions(-) create mode 100644 java/src/com/android/inputmethod/latin/DictionaryCollection.java create mode 100644 java/src/com/android/inputmethod/latin/DictionaryFactory.java (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java index 6678082b7..a1b49b475 100644 --- a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java +++ b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java @@ -17,12 +17,11 @@ package com.android.inputmethod.deprecated.languageswitcher; import com.android.inputmethod.keyboard.KeyboardParser; -import com.android.inputmethod.latin.BinaryDictionary; +import com.android.inputmethod.latin.DictionaryFactory; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.Settings; import com.android.inputmethod.latin.SharedPreferencesCompat; import com.android.inputmethod.latin.SubtypeSwitcher; -import com.android.inputmethod.latin.Suggest; import com.android.inputmethod.latin.Utils; import org.xmlpull.v1.XmlPullParserException; @@ -123,20 +122,10 @@ public class InputLanguageSelection extends PreferenceActivity { if (locale == null) return new Pair(false, false); final Resources res = getResources(); final Locale saveLocale = Utils.setSystemLocale(res, locale); - boolean hasDictionary = false; + final boolean hasDictionary = DictionaryFactory.isDictionaryAvailable(this, locale); boolean hasLayout = false; try { - BinaryDictionary bd = BinaryDictionary.initDictionaryFromManager(this, Suggest.DIC_MAIN, - locale, Utils.getMainDictionaryResourceId(res)); - - // Is the dictionary larger than a placeholder? Arbitrarily chose a lower limit of - // 4000-5000 words, whereas the LARGE_DICTIONARY is about 20000+ words. - if (bd.getSize() > Suggest.LARGE_DICTIONARY_THRESHOLD / 4) { - hasDictionary = true; - } - bd.close(); - final String localeStr = locale.toString(); final String[] layoutCountryCodes = KeyboardParser.parseKeyboardLocale( this, R.xml.kbd_qwerty).split(",", -1); diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 5416cd571..d95fb9638 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -21,12 +21,8 @@ import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.ProximityInfo; import android.content.Context; -import android.content.res.AssetFileDescriptor; -import android.util.Log; -import java.io.File; import java.util.Arrays; -import java.util.Locale; /** * Implements a static, compacted, binary dictionary of standard words. @@ -45,16 +41,15 @@ public class BinaryDictionary extends Dictionary { public static final int MAX_WORD_LENGTH = 48; public static final int MAX_WORDS = 18; + @SuppressWarnings("unused") private static final String TAG = "BinaryDictionary"; private static final int MAX_PROXIMITY_CHARS_SIZE = ProximityInfo.MAX_PROXIMITY_CHARS_SIZE; private static final int MAX_BIGRAMS = 60; private static final int TYPED_LETTER_MULTIPLIER = 2; - private static final BinaryDictionary sInstance = new BinaryDictionary(); private int mDicTypeId; private int mNativeDict; - private long mDictLength; private final int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_PROXIMITY_CHARS_SIZE]; private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS]; private final char[] mOutputChars_bigrams = new char[MAX_WORD_LENGTH * MAX_BIGRAMS]; @@ -79,95 +74,32 @@ public class BinaryDictionary extends Dictionary { private int mFlags = 0; - private BinaryDictionary() { - } - /** - * Initializes a dictionary from a raw resource file - * @param context application context for reading resources - * @param resId the resource containing the raw binary dictionary - * @param dicTypeId the type of the dictionary being created, out of the list in Suggest.DIC_* - * @return an initialized instance of BinaryDictionary + * Constructor for the binary dictionary. This is supposed to be called from the + * dictionary factory. + * All implementations should pass null into flagArray, except for testing purposes. + * @param context the context to access the environment from. + * @param filename the name of the file to read through native code. + * @param offset the offset of the dictionary data within the file. + * @param length the length of the binary data. + * @param flagArray the flags to limit the dictionary to, or null for default. */ - public static BinaryDictionary initDictionary(Context context, int resId, int dicTypeId) { - synchronized (sInstance) { - sInstance.closeInternal(); - try { - final AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId); - if (afd == null) { - Log.e(TAG, "Found the resource but it is compressed. resId=" + resId); - return null; - } - final String sourceDir = context.getApplicationInfo().sourceDir; - final File packagePath = new File(sourceDir); - // TODO: Come up with a way to handle a directory. - if (!packagePath.isFile()) { - Log.e(TAG, "sourceDir is not a file: " + sourceDir); - return null; - } - sInstance.loadDictionary(sourceDir, afd.getStartOffset(), afd.getLength()); - sInstance.mDicTypeId = dicTypeId; - } catch (android.content.res.Resources.NotFoundException e) { - Log.e(TAG, "Could not find the resource. resId=" + resId); - return null; - } - } - sInstance.mFlags = Flag.initFlags(ALL_FLAGS, context, SubtypeSwitcher.getInstance()); - return sInstance; - } - - /* package for test */ static BinaryDictionary initDictionary(Context context, File dictionary, - long startOffset, long length, int dicTypeId, Flag[] flagArray) { - synchronized (sInstance) { - sInstance.closeInternal(); - if (dictionary.isFile()) { - sInstance.loadDictionary(dictionary.getAbsolutePath(), startOffset, length); - sInstance.mDicTypeId = dicTypeId; - } else { - Log.e(TAG, "Could not find the file. path=" + dictionary.getAbsolutePath()); - return null; - } - } - sInstance.mFlags = Flag.initFlags(flagArray, context, null); - return sInstance; + public BinaryDictionary(final Context context, + final String filename, final long offset, final long length, Flag[] flagArray) { + // Note: at the moment a binary dictionary is always of the "main" type. + // Initializing this here will help transitioning out of the scheme where + // the Suggest class knows everything about every single dictionary. + mDicTypeId = Suggest.DIC_MAIN; + // TODO: Stop relying on the state of SubtypeSwitcher, get it as a parameter + mFlags = Flag.initFlags(null == flagArray ? ALL_FLAGS : flagArray, context, + SubtypeSwitcher.getInstance()); + loadDictionary(filename, offset, length); } static { Utils.loadNativeLibrary(); } - /** - * Initializes a dictionary from a dictionary pack. - * - * This searches for a content provider providing a dictionary pack for the specified - * locale. If none is found, it falls back to using the resource passed as fallBackResId - * as a dictionary. - * @param context application context for reading resources - * @param dicTypeId the type of the dictionary being created, out of the list in Suggest.DIC_* - * @param locale the locale for which to create the dictionary - * @param fallbackResId the id of the resource to use as a fallback if no pack is found - * @return an initialized instance of BinaryDictionary - */ - public static BinaryDictionary initDictionaryFromManager(Context context, int dicTypeId, - Locale locale, int fallbackResId) { - if (null == locale) { - Log.e(TAG, "No locale defined for dictionary"); - return initDictionary(context, fallbackResId, dicTypeId); - } - synchronized (sInstance) { - sInstance.closeInternal(); - - final AssetFileAddress dictFile = BinaryDictionaryGetter.getDictionaryFile(locale, - context, fallbackResId); - if (null != dictFile) { - sInstance.loadDictionary(dictFile.mFilename, dictFile.mOffset, dictFile.mLength); - sInstance.mDicTypeId = dicTypeId; - } - } - sInstance.mFlags = Flag.initFlags(ALL_FLAGS, context, SubtypeSwitcher.getInstance()); - return sInstance; - } - private native int openNative(String sourceDir, long dictOffset, long dictSize, int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength, int maxWords, int maxAlternatives); @@ -184,7 +116,6 @@ public class BinaryDictionary extends Dictionary { mNativeDict = openNative(path, startOffset, length, TYPED_LETTER_MULTIPLIER, FULL_WORD_SCORE_MULTIPLIER, MAX_WORD_LENGTH, MAX_WORDS, MAX_PROXIMITY_CHARS_SIZE); - mDictLength = length; } @Override @@ -278,10 +209,6 @@ public class BinaryDictionary extends Dictionary { return isValidWordNative(mNativeDict, chars, chars.length); } - public long getSize() { - return mDictLength; // This value is initialized in loadDictionary() - } - @Override public synchronized void close() { closeInternal(); @@ -291,7 +218,6 @@ public class BinaryDictionary extends Dictionary { if (mNativeDict != 0) { closeNative(mNativeDict); mNativeDict = 0; - mDictLength = 0; } } diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java new file mode 100644 index 000000000..4b64e5344 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java @@ -0,0 +1,66 @@ +/* + * 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.List; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Class for a collection of dictionaries that behave like one dictionary. + */ +public class DictionaryCollection extends Dictionary { + + protected final List mDictionaries; + + public DictionaryCollection() { + mDictionaries = new CopyOnWriteArrayList(); + } + + public DictionaryCollection(Dictionary... dictionaries) { + mDictionaries = new CopyOnWriteArrayList(dictionaries); + } + + @Override + public void getWords(final WordComposer composer, final WordCallback callback) { + for (final Dictionary dict : mDictionaries) + dict.getWords(composer, callback); + } + + @Override + public void getBigrams(final WordComposer composer, final CharSequence previousWord, + final WordCallback callback) { + for (final Dictionary dict : mDictionaries) + dict.getBigrams(composer, previousWord, callback); + } + + @Override + public boolean isValidWord(CharSequence word) { + for (final Dictionary dict : mDictionaries) + if (dict.isValidWord(word)) return true; + return false; + } + + @Override + public void close() { + for (final Dictionary dict : mDictionaries) + dict.close(); + } + + public void addDictionary(Dictionary newDict) { + mDictionaries.add(newDict); + } +} diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java new file mode 100644 index 000000000..cd42d7c3d --- /dev/null +++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java @@ -0,0 +1,159 @@ +/* + * 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 android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.util.Log; + +import java.io.File; +import java.util.Locale; + +/** + * Factory for dictionary instances. + */ +public class DictionaryFactory { + + private static String TAG = DictionaryFactory.class.getSimpleName(); + + /** + * Initializes a dictionary from a dictionary pack. + * + * This searches for a content provider providing a dictionary pack for the specified + * locale. If none is found, it falls back to using the resource passed as fallBackResId + * as a dictionary. + * @param context application context for reading resources + * @param locale the locale for which to create the dictionary + * @param fallbackResId the id of the resource to use as a fallback if no pack is found + * @return an initialized instance of Dictionary + */ + public static Dictionary createDictionaryFromManager(Context context, Locale locale, + int fallbackResId) { + if (null == locale) { + Log.e(TAG, "No locale defined for dictionary"); + return new DictionaryCollection(createBinaryDictionary(context, fallbackResId)); + } + + final AssetFileAddress dictFile = BinaryDictionaryGetter.getDictionaryFile(locale, + context, fallbackResId); + if (null == dictFile) return null; + return new DictionaryCollection(new BinaryDictionary(context, + dictFile.mFilename, dictFile.mOffset, dictFile.mLength, null)); + } + + /** + * Initializes a dictionary from a raw resource file + * @param context application context for reading resources + * @param resId the resource containing the raw binary dictionary + * @return an initialized instance of BinaryDictionary + */ + protected static BinaryDictionary createBinaryDictionary(Context context, int resId) { + AssetFileDescriptor afd = null; + try { + // TODO: IMPORTANT: Do not create a dictionary from a placeholder. + afd = context.getResources().openRawResourceFd(resId); + if (afd == null) { + Log.e(TAG, "Found the resource but it is compressed. resId=" + resId); + return null; + } + if (!isFullDictionary(afd)) return null; + final String sourceDir = context.getApplicationInfo().sourceDir; + final File packagePath = new File(sourceDir); + // TODO: Come up with a way to handle a directory. + if (!packagePath.isFile()) { + Log.e(TAG, "sourceDir is not a file: " + sourceDir); + return null; + } + return new BinaryDictionary(context, + sourceDir, afd.getStartOffset(), afd.getLength(), null); + } catch (android.content.res.Resources.NotFoundException e) { + Log.e(TAG, "Could not find the resource. resId=" + resId); + return null; + } finally { + if (null != afd) { + try { + afd.close(); + } catch (java.io.IOException e) { + /* IOException on close ? What am I supposed to do ? */ + } + } + } + } + + /** + * Create a dictionary from passed data. This is intended for unit tests only. + * @param context the test context to create this data from. + * @param dictionary the file to read + * @param startOffset the offset in the file where the data starts + * @param length the length of the data + * @param flagArray the flags to use with this data for testing + * @return the created dictionary, or null. + */ + public static Dictionary createDictionaryForTest(Context context, File dictionary, + long startOffset, long length, Flag[] flagArray) { + if (dictionary.isFile()) { + return new BinaryDictionary(context, dictionary.getAbsolutePath(), startOffset, length, + flagArray); + } else { + Log.e(TAG, "Could not find the file. path=" + dictionary.getAbsolutePath()); + return null; + } + } + + /** + * Find out whether a dictionary is available for this locale. + * @param context the context on which to check resources. + * @param locale the locale to check for. + * @return whether a (non-placeholder) dictionary is available or not. + */ + public static boolean isDictionaryAvailable(Context context, Locale locale) { + final Resources res = context.getResources(); + final Configuration conf = res.getConfiguration(); + final Locale saveLocale = conf.locale; + conf.locale = locale; + res.updateConfiguration(conf, res.getDisplayMetrics()); + + final int resourceId = Utils.getMainDictionaryResourceId(res); + final AssetFileDescriptor afd = context.getResources().openRawResourceFd(resourceId); + final boolean hasDictionary = isFullDictionary(afd); + try { + if (null != afd) afd.close(); + } catch (java.io.IOException e) { + /* Um, what can we do here exactly? */ + } + + conf.locale = saveLocale; + res.updateConfiguration(conf, res.getDisplayMetrics()); + return hasDictionary; + } + + // TODO: Find the Right Way to find out whether the resource is a placeholder or not. + // Suggestion : strip the locale, open the placeholder file and store its offset. + // Upon opening the file, if it's the same offset, then it's the placeholder. + private static final long PLACEHOLDER_LENGTH = 34; + /** + * Finds out whether the data pointed out by an AssetFileDescriptor is a full + * dictionary (as opposed to null, or to a place holder). + * @param afd the file descriptor to test, or null + * @return true if the dictionary is a real full dictionary, false if it's null or a placeholder + */ + protected static boolean isFullDictionary(final AssetFileDescriptor afd) { + return (afd != null && afd.getLength() > PLACEHOLDER_LENGTH); + } +} diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 1f6146a6d..ca75866c0 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -75,13 +75,11 @@ public class Suggest implements Dictionary.WordCallback { public static final String DICT_KEY_USER_BIGRAM = "user_bigram"; public static final String DICT_KEY_WHITELIST ="whitelist"; - public static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000; - private static final boolean DBG = LatinImeLogger.sDBG; private AutoCorrection mAutoCorrection; - private BinaryDictionary mMainDict; + private Dictionary mMainDict; private WhitelistDictionary mWhiteListDictionary; private final Map mUnigramDictionaries = new HashMap(); private final Map mBigramDictionaries = new HashMap(); @@ -108,17 +106,17 @@ public class Suggest implements Dictionary.WordCallback { private int mCorrectionMode = CORRECTION_BASIC; public Suggest(Context context, int dictionaryResId, Locale locale) { - init(context, BinaryDictionary.initDictionaryFromManager(context, DIC_MAIN, locale, + init(context, DictionaryFactory.createDictionaryFromManager(context, locale, dictionaryResId)); } /* package for test */ Suggest(Context context, File dictionary, long startOffset, long length, Flag[] flagArray) { - init(null, BinaryDictionary.initDictionary(context, dictionary, startOffset, length, - DIC_MAIN, flagArray)); + init(null, DictionaryFactory.createDictionaryForTest(context, dictionary, startOffset, + length, flagArray)); } - private void init(Context context, BinaryDictionary mainDict) { + private void init(Context context, Dictionary mainDict) { if (mainDict != null) { mMainDict = mainDict; mUnigramDictionaries.put(DICT_KEY_MAIN, mainDict); @@ -133,8 +131,8 @@ public class Suggest implements Dictionary.WordCallback { } public void resetMainDict(Context context, int dictionaryResId, Locale locale) { - final BinaryDictionary newMainDict = BinaryDictionary.initDictionaryFromManager(context, - DIC_MAIN, locale, dictionaryResId); + final Dictionary newMainDict = DictionaryFactory.createDictionaryFromManager( + context, locale, dictionaryResId); mMainDict = newMainDict; if (null == newMainDict) { mUnigramDictionaries.remove(DICT_KEY_MAIN); @@ -165,7 +163,7 @@ public class Suggest implements Dictionary.WordCallback { } public boolean hasMainDictionary() { - return mMainDict != null && mMainDict.getSize() > LARGE_DICTIONARY_THRESHOLD; + return mMainDict != null; } public Map getUnigramDictionaries() { -- cgit v1.2.3-83-g751a From 19bfef6cb0714a46a276abe45329e4abb661f76e Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 27 Apr 2011 17:10:18 +0900 Subject: Use the new Utils.setSystemLocale method in the new code. The change list that introduced this code was created at the same time as the one that introduced the Utils.setSystemLocale method and didn't use it yet. Fix this. Change-Id: Ifdd2ad9f7dbb7f300bc255bc2e035ae893a9d410 --- java/src/com/android/inputmethod/latin/DictionaryFactory.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java index cd42d7c3d..2dbd582f3 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java @@ -124,13 +124,10 @@ public class DictionaryFactory { */ public static boolean isDictionaryAvailable(Context context, Locale locale) { final Resources res = context.getResources(); - final Configuration conf = res.getConfiguration(); - final Locale saveLocale = conf.locale; - conf.locale = locale; - res.updateConfiguration(conf, res.getDisplayMetrics()); + final Locale saveLocale = Utils.setSystemLocale(res, locale); final int resourceId = Utils.getMainDictionaryResourceId(res); - final AssetFileDescriptor afd = context.getResources().openRawResourceFd(resourceId); + final AssetFileDescriptor afd = res.openRawResourceFd(resourceId); final boolean hasDictionary = isFullDictionary(afd); try { if (null != afd) afd.close(); @@ -138,8 +135,7 @@ public class DictionaryFactory { /* Um, what can we do here exactly? */ } - conf.locale = saveLocale; - res.updateConfiguration(conf, res.getDisplayMetrics()); + Utils.setSystemLocale(res, saveLocale); return hasDictionary; } -- cgit v1.2.3-83-g751a