From b03447e1af950888d901fccbd2cc3e3b4a11ef98 Mon Sep 17 00:00:00 2001 From: Ken Wakasa Date: Thu, 18 Jul 2013 22:59:26 +0900 Subject: Move a couple classes to the utils package Change-Id: Ia14a2011d79bad7cd02697b9254705f6e2099442 --- .../android/inputmethod/latin/AutoCorrection.java | 135 -------------------- .../inputmethod/latin/ByteArrayWrapper.java | 81 ------------ .../com/android/inputmethod/latin/LatinIME.java | 5 +- .../src/com/android/inputmethod/latin/Suggest.java | 5 +- .../inputmethod/latin/UserHistoryDictionary.java | 1 + .../suggestions/SuggestionStripLayoutHelper.java | 4 +- .../latin/utils/AutoCorrectionUtils.java | 139 +++++++++++++++++++++ .../inputmethod/latin/utils/ByteArrayWrapper.java | 81 ++++++++++++ 8 files changed, 229 insertions(+), 222 deletions(-) delete mode 100644 java/src/com/android/inputmethod/latin/AutoCorrection.java delete mode 100644 java/src/com/android/inputmethod/latin/ByteArrayWrapper.java create mode 100644 java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java create mode 100644 java/src/com/android/inputmethod/latin/utils/ByteArrayWrapper.java (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java deleted file mode 100644 index 86be4295a..000000000 --- a/java/src/com/android/inputmethod/latin/AutoCorrection.java +++ /dev/null @@ -1,135 +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 com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; - -import android.text.TextUtils; -import android.util.Log; - -import java.util.concurrent.ConcurrentHashMap; - -public final class AutoCorrection { - private static final boolean DBG = LatinImeLogger.sDBG; - private static final String TAG = AutoCorrection.class.getSimpleName(); - private static final int MINIMUM_SAFETY_NET_CHAR_LENGTH = 4; - - private AutoCorrection() { - // Purely static class: can't instantiate. - } - - public static boolean isValidWord(final Suggest suggest, final String word, - final boolean ignoreCase) { - if (TextUtils.isEmpty(word)) { - return false; - } - final ConcurrentHashMap dictionaries = suggest.getUnigramDictionaries(); - final String lowerCasedWord = word.toLowerCase(suggest.mLocale); - for (final String key : dictionaries.keySet()) { - final Dictionary dictionary = dictionaries.get(key); - // It's unclear how realistically 'dictionary' can be null, but the monkey is somehow - // managing to get null in here. Presumably the language is changing to a language with - // no main dictionary and the monkey manages to type a whole word before the thread - // that reads the dictionary is started or something? - // Ideally the passed map would come out of a {@link java.util.concurrent.Future} and - // would be immutable once it's finished initializing, but concretely a null test is - // probably good enough for the time being. - if (null == dictionary) continue; - if (dictionary.isValidWord(word) - || (ignoreCase && dictionary.isValidWord(lowerCasedWord))) { - return true; - } - } - return false; - } - - public static int getMaxFrequency(final ConcurrentHashMap dictionaries, - final String word) { - if (TextUtils.isEmpty(word)) { - return Dictionary.NOT_A_PROBABILITY; - } - int maxFreq = -1; - for (final String key : dictionaries.keySet()) { - final Dictionary dictionary = dictionaries.get(key); - if (null == dictionary) continue; - final int tempFreq = dictionary.getFrequency(word); - if (tempFreq >= maxFreq) { - maxFreq = tempFreq; - } - } - return maxFreq; - } - - public static boolean suggestionExceedsAutoCorrectionThreshold( - final SuggestedWordInfo suggestion, final String consideredWord, - final float autoCorrectionThreshold) { - if (null != suggestion) { - // Shortlist a whitelisted word - if (suggestion.mKind == SuggestedWordInfo.KIND_WHITELIST) return true; - final int autoCorrectionSuggestionScore = suggestion.mScore; - // TODO: when the normalized score of the first suggestion is nearly equals to - // the normalized score of the second suggestion, behave less aggressive. - final float normalizedScore = BinaryDictionary.calcNormalizedScore( - consideredWord, suggestion.mWord, autoCorrectionSuggestionScore); - if (DBG) { - Log.d(TAG, "Normalized " + consideredWord + "," + suggestion + "," - + autoCorrectionSuggestionScore + ", " + normalizedScore - + "(" + autoCorrectionThreshold + ")"); - } - if (normalizedScore >= autoCorrectionThreshold) { - if (DBG) { - Log.d(TAG, "Auto corrected by S-threshold."); - } - return !shouldBlockAutoCorrectionBySafetyNet(consideredWord, suggestion.mWord); - } - } - return false; - } - - // TODO: Resolve the inconsistencies between the native auto correction algorithms and - // this safety net - public static boolean shouldBlockAutoCorrectionBySafetyNet(final String typedWord, - final String suggestion) { - // Safety net for auto correction. - // Actually if we hit this safety net, it's a bug. - // If user selected aggressive auto correction mode, there is no need to use the safety - // net. - // If the length of typed word is less than MINIMUM_SAFETY_NET_CHAR_LENGTH, - // we should not use net because relatively edit distance can be big. - final int typedWordLength = typedWord.length(); - if (typedWordLength < MINIMUM_SAFETY_NET_CHAR_LENGTH) { - return false; - } - final int maxEditDistanceOfNativeDictionary = - (typedWordLength < 5 ? 2 : typedWordLength / 2) + 1; - final int distance = BinaryDictionary.editDistance(typedWord, suggestion); - if (DBG) { - Log.d(TAG, "Autocorrected edit distance = " + distance - + ", " + maxEditDistanceOfNativeDictionary); - } - if (distance > maxEditDistanceOfNativeDictionary) { - if (DBG) { - Log.e(TAG, "Safety net: before = " + typedWord + ", after = " + suggestion); - Log.e(TAG, "(Error) The edit distance of this correction exceeds limit. " - + "Turning off auto-correction."); - } - return true; - } else { - return false; - } - } -} diff --git a/java/src/com/android/inputmethod/latin/ByteArrayWrapper.java b/java/src/com/android/inputmethod/latin/ByteArrayWrapper.java deleted file mode 100644 index 15f70c50c..000000000 --- a/java/src/com/android/inputmethod/latin/ByteArrayWrapper.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2013 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 com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface; - -/** - * This class provides an implementation for the FusionDictionary buffer interface that is backed - * by a simpled byte array. It allows to create a binary dictionary in memory. - */ -public final class ByteArrayWrapper implements FusionDictionaryBufferInterface { - private byte[] mBuffer; - private int mPosition; - - public ByteArrayWrapper(final byte[] buffer) { - mBuffer = buffer; - mPosition = 0; - } - - @Override - public int readUnsignedByte() { - return mBuffer[mPosition++] & 0xFF; - } - - @Override - public int readUnsignedShort() { - final int retval = readUnsignedByte(); - return (retval << 8) + readUnsignedByte(); - } - - @Override - public int readUnsignedInt24() { - final int retval = readUnsignedShort(); - return (retval << 8) + readUnsignedByte(); - } - - @Override - public int readInt() { - final int retval = readUnsignedShort(); - return (retval << 16) + readUnsignedShort(); - } - - @Override - public int position() { - return mPosition; - } - - @Override - public void position(int position) { - mPosition = position; - } - - @Override - public void put(final byte b) { - mBuffer[mPosition++] = b; - } - - @Override - public int limit() { - return mBuffer.length - 1; - } - - @Override - public int capacity() { - return mBuffer.length; - } -} diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 7890dbb3f..1e2a1a6bd 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -77,6 +77,7 @@ import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.latin.suggestions.SuggestionStripView; import com.android.inputmethod.latin.utils.ApplicationUtils; +import com.android.inputmethod.latin.utils.AutoCorrectionUtils; import com.android.inputmethod.latin.utils.CapsModeUtils; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.CompletionInfoUtils; @@ -2428,7 +2429,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen || SuggestedWordInfo.KIND_OOV_CORRECTION == suggestionInfo.mKind) && mSuggest != null // If the suggestion is not in the dictionary, the hint should be shown. - && !AutoCorrection.isValidWord(mSuggest, suggestion, true); + && !AutoCorrectionUtils.isValidWord(mSuggest, suggestion, true); if (mSettings.isInternal()) { LatinImeLoggerUtils.onSeparator((char)Constants.CODE_SPACE, @@ -2496,7 +2497,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } // We demote unrecognized words (frequency < 0, below) by specifying them as "invalid". // We don't add words with 0-frequency (assuming they would be profanity etc.). - final int maxFreq = AutoCorrection.getMaxFrequency( + final int maxFreq = AutoCorrectionUtils.getMaxFrequency( suggest.getUnigramDictionaries(), suggestion); if (maxFreq == 0) return null; userHistoryDictionary.addToUserHistory(prevWord, secondWord, maxFreq > 0); diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 8b31f4e99..ac497ec9f 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -22,6 +22,7 @@ import android.text.TextUtils; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.utils.AutoCorrectionUtils; import com.android.inputmethod.latin.utils.BoundedTreeSet; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.StringUtils; @@ -231,7 +232,7 @@ public final class Suggest { // or if it's a 2+ characters non-word (i.e. it's not in the dictionary). final boolean allowsToBeAutoCorrected = (null != whitelistedWord && !whitelistedWord.equals(consideredWord)) - || (consideredWord.length() > 1 && !AutoCorrection.isValidWord(this, + || (consideredWord.length() > 1 && !AutoCorrectionUtils.isValidWord(this, consideredWord, wordComposer.isFirstCharCapitalized())); final boolean hasAutoCorrection; @@ -252,7 +253,7 @@ public final class Suggest { // auto-correct. hasAutoCorrection = false; } else { - hasAutoCorrection = AutoCorrection.suggestionExceedsAutoCorrectionThreshold( + hasAutoCorrection = AutoCorrectionUtils.suggestionExceedsAutoCorrectionThreshold( suggestionsSet.first(), consideredWord, mAutoCorrectionThreshold); } diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java index 8c668b810..2370ebe43 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java @@ -25,6 +25,7 @@ import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; +import com.android.inputmethod.latin.utils.ByteArrayWrapper; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils; import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.BigramDictionaryInterface; diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java index ce340b666..1dd04fc4d 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java @@ -45,10 +45,10 @@ import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; -import com.android.inputmethod.latin.AutoCorrection; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.utils.AutoCorrectionUtils; import com.android.inputmethod.latin.utils.ResourceUtils; import com.android.inputmethod.latin.utils.ViewLayoutUtils; @@ -279,7 +279,7 @@ final class SuggestionStripLayoutHelper { // If we auto-correct, then the autocorrection is in slot 0 and the typed word // is in slot 1. if (positionInStrip == mCenterPositionInStrip - && AutoCorrection.shouldBlockAutoCorrectionBySafetyNet( + && AutoCorrectionUtils.shouldBlockAutoCorrectionBySafetyNet( suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION), suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD))) { return 0xFFFF0000; diff --git a/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java b/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java new file mode 100644 index 000000000..066c5fd32 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java @@ -0,0 +1,139 @@ +/* + * 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.utils; + +import com.android.inputmethod.latin.BinaryDictionary; +import com.android.inputmethod.latin.Dictionary; +import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.Suggest; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; + +import android.text.TextUtils; +import android.util.Log; + +import java.util.concurrent.ConcurrentHashMap; + +public final class AutoCorrectionUtils { + private static final boolean DBG = LatinImeLogger.sDBG; + private static final String TAG = AutoCorrectionUtils.class.getSimpleName(); + private static final int MINIMUM_SAFETY_NET_CHAR_LENGTH = 4; + + private AutoCorrectionUtils() { + // Purely static class: can't instantiate. + } + + public static boolean isValidWord(final Suggest suggest, final String word, + final boolean ignoreCase) { + if (TextUtils.isEmpty(word)) { + return false; + } + final ConcurrentHashMap dictionaries = suggest.getUnigramDictionaries(); + final String lowerCasedWord = word.toLowerCase(suggest.mLocale); + for (final String key : dictionaries.keySet()) { + final Dictionary dictionary = dictionaries.get(key); + // It's unclear how realistically 'dictionary' can be null, but the monkey is somehow + // managing to get null in here. Presumably the language is changing to a language with + // no main dictionary and the monkey manages to type a whole word before the thread + // that reads the dictionary is started or something? + // Ideally the passed map would come out of a {@link java.util.concurrent.Future} and + // would be immutable once it's finished initializing, but concretely a null test is + // probably good enough for the time being. + if (null == dictionary) continue; + if (dictionary.isValidWord(word) + || (ignoreCase && dictionary.isValidWord(lowerCasedWord))) { + return true; + } + } + return false; + } + + public static int getMaxFrequency(final ConcurrentHashMap dictionaries, + final String word) { + if (TextUtils.isEmpty(word)) { + return Dictionary.NOT_A_PROBABILITY; + } + int maxFreq = -1; + for (final String key : dictionaries.keySet()) { + final Dictionary dictionary = dictionaries.get(key); + if (null == dictionary) continue; + final int tempFreq = dictionary.getFrequency(word); + if (tempFreq >= maxFreq) { + maxFreq = tempFreq; + } + } + return maxFreq; + } + + public static boolean suggestionExceedsAutoCorrectionThreshold( + final SuggestedWordInfo suggestion, final String consideredWord, + final float autoCorrectionThreshold) { + if (null != suggestion) { + // Shortlist a whitelisted word + if (suggestion.mKind == SuggestedWordInfo.KIND_WHITELIST) return true; + final int autoCorrectionSuggestionScore = suggestion.mScore; + // TODO: when the normalized score of the first suggestion is nearly equals to + // the normalized score of the second suggestion, behave less aggressive. + final float normalizedScore = BinaryDictionary.calcNormalizedScore( + consideredWord, suggestion.mWord, autoCorrectionSuggestionScore); + if (DBG) { + Log.d(TAG, "Normalized " + consideredWord + "," + suggestion + "," + + autoCorrectionSuggestionScore + ", " + normalizedScore + + "(" + autoCorrectionThreshold + ")"); + } + if (normalizedScore >= autoCorrectionThreshold) { + if (DBG) { + Log.d(TAG, "Auto corrected by S-threshold."); + } + return !shouldBlockAutoCorrectionBySafetyNet(consideredWord, suggestion.mWord); + } + } + return false; + } + + // TODO: Resolve the inconsistencies between the native auto correction algorithms and + // this safety net + public static boolean shouldBlockAutoCorrectionBySafetyNet(final String typedWord, + final String suggestion) { + // Safety net for auto correction. + // Actually if we hit this safety net, it's a bug. + // If user selected aggressive auto correction mode, there is no need to use the safety + // net. + // If the length of typed word is less than MINIMUM_SAFETY_NET_CHAR_LENGTH, + // we should not use net because relatively edit distance can be big. + final int typedWordLength = typedWord.length(); + if (typedWordLength < MINIMUM_SAFETY_NET_CHAR_LENGTH) { + return false; + } + final int maxEditDistanceOfNativeDictionary = + (typedWordLength < 5 ? 2 : typedWordLength / 2) + 1; + final int distance = BinaryDictionary.editDistance(typedWord, suggestion); + if (DBG) { + Log.d(TAG, "Autocorrected edit distance = " + distance + + ", " + maxEditDistanceOfNativeDictionary); + } + if (distance > maxEditDistanceOfNativeDictionary) { + if (DBG) { + Log.e(TAG, "Safety net: before = " + typedWord + ", after = " + suggestion); + Log.e(TAG, "(Error) The edit distance of this correction exceeds limit. " + + "Turning off auto-correction."); + } + return true; + } else { + return false; + } + } +} diff --git a/java/src/com/android/inputmethod/latin/utils/ByteArrayWrapper.java b/java/src/com/android/inputmethod/latin/utils/ByteArrayWrapper.java new file mode 100644 index 000000000..1bb27aa2b --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/ByteArrayWrapper.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2013 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.utils; + +import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface; + +/** + * This class provides an implementation for the FusionDictionary buffer interface that is backed + * by a simpled byte array. It allows to create a binary dictionary in memory. + */ +public final class ByteArrayWrapper implements FusionDictionaryBufferInterface { + private byte[] mBuffer; + private int mPosition; + + public ByteArrayWrapper(final byte[] buffer) { + mBuffer = buffer; + mPosition = 0; + } + + @Override + public int readUnsignedByte() { + return mBuffer[mPosition++] & 0xFF; + } + + @Override + public int readUnsignedShort() { + final int retval = readUnsignedByte(); + return (retval << 8) + readUnsignedByte(); + } + + @Override + public int readUnsignedInt24() { + final int retval = readUnsignedShort(); + return (retval << 8) + readUnsignedByte(); + } + + @Override + public int readInt() { + final int retval = readUnsignedShort(); + return (retval << 16) + readUnsignedShort(); + } + + @Override + public int position() { + return mPosition; + } + + @Override + public void position(int position) { + mPosition = position; + } + + @Override + public void put(final byte b) { + mBuffer[mPosition++] = b; + } + + @Override + public int limit() { + return mBuffer.length - 1; + } + + @Override + public int capacity() { + return mBuffer.length; + } +} -- cgit v1.2.3-83-g751a