1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.inputmethod.latin; 18 19 import android.text.TextUtils; 20 import android.util.Log; 21 22 import java.util.ArrayList; 23 import java.util.Map; 24 25 public class AutoCorrection { 26 private static final boolean DBG = LatinImeLogger.sDBG; 27 private static final String TAG = AutoCorrection.class.getSimpleName(); 28 private boolean mHasAutoCorrection; 29 private CharSequence mAutoCorrectionWord; 30 private double mNormalizedScore; 31 32 public void init() { 33 mHasAutoCorrection = false; 34 mAutoCorrectionWord = null; 35 mNormalizedScore = Integer.MIN_VALUE; 36 } 37 38 public boolean hasAutoCorrection() { 39 return mHasAutoCorrection; 40 } 41 42 public CharSequence getAutoCorrectionWord() { 43 return mAutoCorrectionWord; 44 } 45 46 public double getNormalizedScore() { 47 return mNormalizedScore; 48 } 49 50 public void updateAutoCorrectionStatus(Map<String, Dictionary> dictionaries, 51 WordComposer wordComposer, ArrayList<CharSequence> suggestions, int[] sortedScores, 52 CharSequence typedWord, double autoCorrectionThreshold, int correctionMode, 53 CharSequence whitelistedWord) { 54 if (hasAutoCorrectionForWhitelistedWord(whitelistedWord)) { 55 mHasAutoCorrection = true; 56 mAutoCorrectionWord = whitelistedWord; 57 } else if (hasAutoCorrectionForTypedWord( 58 dictionaries, wordComposer, suggestions, typedWord, correctionMode)) { 59 mHasAutoCorrection = true; 60 mAutoCorrectionWord = typedWord; 61 } else if (hasAutoCorrectionForBinaryDictionary(wordComposer, suggestions, correctionMode, 62 sortedScores, typedWord, autoCorrectionThreshold)) { 63 mHasAutoCorrection = true; 64 mAutoCorrectionWord = suggestions.get(0); 65 } 66 } 67 68 public static boolean isValidWord( 69 Map<String, Dictionary> dictionaries, CharSequence word, boolean ignoreCase) { 70 if (TextUtils.isEmpty(word)) { 71 return false; 72 } 73 final CharSequence lowerCasedWord = word.toString().toLowerCase(); 74 for (final String key : dictionaries.keySet()) { 75 if (key.equals(Suggest.DICT_KEY_WHITELIST)) continue; 76 final Dictionary dictionary = dictionaries.get(key); 77 if (dictionary.isValidWord(word) 78 || (ignoreCase && dictionary.isValidWord(lowerCasedWord))) { 79 return true; 80 } 81 } 82 return false; 83 } 84 85 public static boolean allowsToBeAutoCorrected( 86 Map<String, Dictionary> dictionaries, CharSequence word, boolean ignoreCase) { 87 final WhitelistDictionary whitelistDictionary = 88 (WhitelistDictionary)dictionaries.get(Suggest.DICT_KEY_WHITELIST); 89 // If "word" is in the whitelist dictionary, it should not be auto corrected. 90 if (whitelistDictionary != null 91 && whitelistDictionary.shouldForciblyAutoCorrectFrom(word)) { 92 return true; 93 } 94 return !isValidWord(dictionaries, word, ignoreCase); 95 } 96 97 private static boolean hasAutoCorrectionForWhitelistedWord(CharSequence whiteListedWord) { 98 return whiteListedWord != null; 99 } 100 101 private boolean hasAutoCorrectionForTypedWord(Map<String, Dictionary> dictionaries, 102 WordComposer wordComposer, ArrayList<CharSequence> suggestions, CharSequence typedWord, 103 int correctionMode) { 104 if (TextUtils.isEmpty(typedWord)) return false; 105 boolean allowsAutoCorrect = allowsToBeAutoCorrected(dictionaries, typedWord, false); 106 return wordComposer.size() > 1 && suggestions.size() > 0 && !allowsAutoCorrect 107 && (correctionMode == Suggest.CORRECTION_FULL 108 || correctionMode == Suggest.CORRECTION_FULL_BIGRAM); 109 } 110 111 private boolean hasAutoCorrectionForBinaryDictionary(WordComposer wordComposer, 112 ArrayList<CharSequence> suggestions, int correctionMode, int[] sortedScores, 113 CharSequence typedWord, double autoCorrectionThreshold) { 114 if (wordComposer.size() > 1 && (correctionMode == Suggest.CORRECTION_FULL 115 || correctionMode == Suggest.CORRECTION_FULL_BIGRAM) 116 && typedWord != null && suggestions.size() > 0 && sortedScores.length > 0) { 117 final CharSequence autoCorrectionSuggestion = suggestions.get(0); 118 final int autoCorrectionSuggestionScore = sortedScores[0]; 119 // TODO: when the normalized score of the first suggestion is nearly equals to 120 // the normalized score of the second suggestion, behave less aggressive. 121 mNormalizedScore = Utils.calcNormalizedScore( 122 typedWord,autoCorrectionSuggestion, autoCorrectionSuggestionScore); 123 if (DBG) { 124 Log.d(TAG, "Normalized " + typedWord + "," + autoCorrectionSuggestion + "," 125 + autoCorrectionSuggestionScore + ", " + mNormalizedScore 126 + "(" + autoCorrectionThreshold + ")"); 127 } 128 if (mNormalizedScore >= autoCorrectionThreshold) { 129 if (DBG) { 130 Log.d(TAG, "Auto corrected by S-threshold."); 131 } 132 return true; 133 } 134 } 135 return false; 136 } 137 138 } 139