Home | History | Annotate | Download | only in latin
      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