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.utils;
18 
19 import android.util.Log;
20 
21 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
22 import com.android.inputmethod.latin.define.DebugFlags;
23 
24 public final class AutoCorrectionUtils {
25     private static final boolean DBG = DebugFlags.DEBUG_ENABLED;
26     private static final String TAG = AutoCorrectionUtils.class.getSimpleName();
27     private static final int MINIMUM_SAFETY_NET_CHAR_LENGTH = 4;
28 
AutoCorrectionUtils()29     private AutoCorrectionUtils() {
30         // Purely static class: can't instantiate.
31     }
32 
suggestionExceedsAutoCorrectionThreshold( final SuggestedWordInfo suggestion, final String consideredWord, final float autoCorrectionThreshold)33     public static boolean suggestionExceedsAutoCorrectionThreshold(
34             final SuggestedWordInfo suggestion, final String consideredWord,
35             final float autoCorrectionThreshold) {
36         if (null != suggestion) {
37             // Shortlist a whitelisted word
38             if (suggestion.isKindOf(SuggestedWordInfo.KIND_WHITELIST)) {
39                 return true;
40             }
41             final int autoCorrectionSuggestionScore = suggestion.mScore;
42             // TODO: when the normalized score of the first suggestion is nearly equals to
43             //       the normalized score of the second suggestion, behave less aggressive.
44             final float normalizedScore = BinaryDictionaryUtils.calcNormalizedScore(
45                     consideredWord, suggestion.mWord, autoCorrectionSuggestionScore);
46             if (DBG) {
47                 Log.d(TAG, "Normalized " + consideredWord + "," + suggestion + ","
48                         + autoCorrectionSuggestionScore + ", " + normalizedScore
49                         + "(" + autoCorrectionThreshold + ")");
50             }
51             if (normalizedScore >= autoCorrectionThreshold) {
52                 if (DBG) {
53                     Log.d(TAG, "Auto corrected by S-threshold.");
54                 }
55                 return !shouldBlockAutoCorrectionBySafetyNet(consideredWord, suggestion.mWord);
56             }
57         }
58         return false;
59     }
60 
61     // TODO: Resolve the inconsistencies between the native auto correction algorithms and
62     // this safety net
shouldBlockAutoCorrectionBySafetyNet(final String typedWord, final String suggestion)63     public static boolean shouldBlockAutoCorrectionBySafetyNet(final String typedWord,
64             final String suggestion) {
65         // Safety net for auto correction.
66         // Actually if we hit this safety net, it's a bug.
67         // If user selected aggressive auto correction mode, there is no need to use the safety
68         // net.
69         // If the length of typed word is less than MINIMUM_SAFETY_NET_CHAR_LENGTH,
70         // we should not use net because relatively edit distance can be big.
71         final int typedWordLength = typedWord.length();
72         if (typedWordLength < MINIMUM_SAFETY_NET_CHAR_LENGTH) {
73             return false;
74         }
75         final int maxEditDistanceOfNativeDictionary = (typedWordLength / 2) + 1;
76         final int distance = BinaryDictionaryUtils.editDistance(typedWord, suggestion);
77         if (DBG) {
78             Log.d(TAG, "Autocorrected edit distance = " + distance
79                     + ", " + maxEditDistanceOfNativeDictionary);
80         }
81         if (distance > maxEditDistanceOfNativeDictionary) {
82             if (DBG) {
83                 Log.e(TAG, "Safety net: before = " + typedWord + ", after = " + suggestion);
84                 Log.e(TAG, "(Error) The edit distance of this correction exceeds limit. "
85                         + "Turning off auto-correction.");
86             }
87             return true;
88         } else {
89             return false;
90         }
91     }
92 }
93