From 9f67e12a0e3f77985fb8bafe0db4c00e32317b9a Mon Sep 17 00:00:00 2001
From: satok <satok@google.com>
Date: Wed, 2 Mar 2011 15:40:08 +0900
Subject: [PATCH] Move the auto correction functionalities to
 AutoCorrection.java

- Also removed a quick fix for 2nd or more suggestions.

Change-Id: I7bf46a9cd6a727473e68836954fca160c9d853e6
---
 .../inputmethod/latin/AutoCorrection.java     | 103 ++++++++++++++++
 .../android/inputmethod/latin/LatinIME.java   |   3 +-
 .../android/inputmethod/latin/Suggest.java    | 114 ++++++++----------
 3 files changed, 154 insertions(+), 66 deletions(-)
 create mode 100644 java/src/com/android/inputmethod/latin/AutoCorrection.java

diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java
new file mode 100644
index 0000000000..d1154d9ed6
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java
@@ -0,0 +1,103 @@
+/*
+ * 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.util.Log;
+
+import java.util.ArrayList;
+
+public class AutoCorrection {
+    private static final boolean DBG = LatinImeLogger.sDBG;
+    private static final String TAG = AutoCorrection.class.getSimpleName();
+    private boolean mHasAutoCorrection;
+    private CharSequence mAutoCorrectionWord;
+    private double mNormalizedScore;
+
+    public void init() {
+        mHasAutoCorrection = false;
+        mAutoCorrectionWord = null;
+        mNormalizedScore = Integer.MIN_VALUE;
+    }
+
+    public boolean hasAutoCorrection() {
+        return mHasAutoCorrection;
+    }
+
+    public CharSequence getAutoCorrectionWord() {
+        return mAutoCorrectionWord;
+    }
+
+    public double getNormalizedScore() {
+        return mNormalizedScore;
+    }
+
+    public void updateAutoCorrectionStatus(Suggest suggest,
+            WordComposer wordComposer, ArrayList<CharSequence> suggestions, int[] priorities,
+            CharSequence typedWord, double autoCorrectionThreshold, int correctionMode,
+            CharSequence quickFixedWord) {
+        if (hasAutoCorrectionForTypedWord(
+                suggest, wordComposer, suggestions, typedWord, correctionMode)) {
+            mHasAutoCorrection = true;
+            mAutoCorrectionWord = typedWord;
+        } else if (hasAutoCorrectForBinaryDictionary(wordComposer, suggestions, correctionMode,
+                priorities, typedWord, autoCorrectionThreshold)) {
+            mHasAutoCorrection = true;
+            mAutoCorrectionWord = suggestions.get(0);
+        } else if (hasAutoCorrectionForQuickFix(quickFixedWord)) {
+            mHasAutoCorrection = true;
+            mAutoCorrectionWord = quickFixedWord;
+        }
+    }
+
+    private boolean hasAutoCorrectionForTypedWord(Suggest suggest, WordComposer wordComposer,
+            ArrayList<CharSequence> suggestions, CharSequence typedWord, int correctionMode) {
+        return wordComposer.size() > 1 && suggestions.size() > 0 && suggest.isValidWord(typedWord)
+                && (correctionMode == Suggest.CORRECTION_FULL
+                || correctionMode == Suggest.CORRECTION_FULL_BIGRAM);
+    }
+
+    private boolean hasAutoCorrectForBinaryDictionary(WordComposer wordComposer,
+            ArrayList<CharSequence> suggestions, int correctionMode, int[] priorities,
+            CharSequence typedWord, double autoCorrectionThreshold) {
+        if (wordComposer.size() > 1 && (correctionMode == Suggest.CORRECTION_FULL
+                || correctionMode == Suggest.CORRECTION_FULL_BIGRAM)
+                && typedWord != null && suggestions.size() > 0 && priorities.length > 0) {
+            final CharSequence autoCorrectionCandidate = suggestions.get(0);
+            final int autoCorrectionCandidateScore = priorities[0];
+            // TODO: when the normalized score of the first suggestion is nearly equals to
+            //       the normalized score of the second suggestion, behave less aggressive.
+            mNormalizedScore = Utils.calcNormalizedScore(
+                    typedWord,autoCorrectionCandidate, autoCorrectionCandidateScore);
+            if (DBG) {
+                Log.d(TAG, "Normalized " + typedWord + "," + autoCorrectionCandidate + ","
+                        + autoCorrectionCandidateScore + ", " + mNormalizedScore
+                        + "(" + autoCorrectionThreshold + ")");
+            }
+            if (mNormalizedScore >= autoCorrectionThreshold) {
+                if (DBG) {
+                    Log.d(TAG, "Auto corrected by S-threshold.");
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean hasAutoCorrectionForQuickFix(CharSequence quickFixedWord) {
+        return quickFixedWord != null;
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 838249a39a..611d362162 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1538,7 +1538,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     }
 
     private void showSuggestions(WordComposer word) {
-        // TODO Maybe need better way of retrieving previous word
+        // TODO: May need a better way of retrieving previous word
         CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
                 mWordSeparators);
         SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
@@ -2059,6 +2059,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     }
 
     private void updateCorrectionMode() {
+        // TODO: cleanup messy flags
         mHasDictionary = mSuggest != null ? mSuggest.hasMainDictionary() : false;
         mAutoCorrectOn = (mAutoCorrectEnabled || mQuickFixes)
                 && !mInputTypeNoAutoCorrect && mHasDictionary;
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index ee6930d93d..95a2d631b6 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -67,6 +67,8 @@ public class Suggest implements Dictionary.WordCallback {
 
     private static final boolean DBG = LatinImeLogger.sDBG;
 
+    private AutoCorrection mAutoCorrection;
+
     private BinaryDictionary mMainDict;
 
     private Dictionary mUserDictionary;
@@ -90,7 +92,6 @@ public class Suggest implements Dictionary.WordCallback {
     private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>();
     ArrayList<CharSequence> mBigramSuggestions  = new ArrayList<CharSequence>();
     private ArrayList<CharSequence> mStringPool = new ArrayList<CharSequence>();
-    private boolean mHasAutoCorrection;
     private String mLowerOriginalWord;
 
     // TODO: Remove these member variables by passing more context to addWord() callback method
@@ -101,12 +102,16 @@ public class Suggest implements Dictionary.WordCallback {
 
     public Suggest(Context context, int dictionaryResId) {
         mMainDict = BinaryDictionary.initDictionary(context, dictionaryResId, DIC_MAIN);
-        initPool();
+        init();
     }
 
-    // For unit test
-    /* package */ Suggest(File dictionary, long startOffset, long length) {
+    /* package for test */ Suggest(File dictionary, long startOffset, long length) {
         mMainDict = BinaryDictionary.initDictionary(dictionary, startOffset, length, DIC_MAIN);
+        init();
+    }
+
+    private void init() {
+        mAutoCorrection = new AutoCorrection();
         initPool();
     }
 
@@ -205,7 +210,7 @@ public class Suggest implements Dictionary.WordCallback {
     public SuggestedWords.Builder getSuggestedWordBuilder(View view, WordComposer wordComposer,
             CharSequence prevWordForBigram) {
         LatinImeLogger.onStartSuggestion(prevWordForBigram);
-        mHasAutoCorrection = false;
+        mAutoCorrection.init();
         mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized();
         mIsAllUpperCase = wordComposer.isAllUpperCase();
         collectGarbage(mSuggestions, mPrefMaxSuggestions);
@@ -224,7 +229,6 @@ public class Suggest implements Dictionary.WordCallback {
             mLowerOriginalWord = "";
         }
 
-        double normalizedScore = Integer.MIN_VALUE;
         if (wordComposer.size() == 1 && (mCorrectionMode == CORRECTION_FULL_BIGRAM
                 || mCorrectionMode == CORRECTION_BASIC)) {
             // At first character typed, search only the bigrams
@@ -273,86 +277,67 @@ public class Suggest implements Dictionary.WordCallback {
                 if (mContactsDictionary != null) {
                     mContactsDictionary.getWords(wordComposer, this);
                 }
-
-                if (mSuggestions.size() > 0 && isValidWord(typedWord)
-                        && (mCorrectionMode == CORRECTION_FULL
-                        || mCorrectionMode == CORRECTION_FULL_BIGRAM)) {
-                    if (DBG) {
-                        Log.d(TAG, "Auto corrected by CORRECTION_FULL.");
-                    }
-                    mHasAutoCorrection = true;
-                }
             }
             if (mMainDict != null) mMainDict.getWords(wordComposer, this);
-            if ((mCorrectionMode == CORRECTION_FULL || mCorrectionMode == CORRECTION_FULL_BIGRAM)
-                    && mSuggestions.size() > 0 && mPriorities.length > 0) {
-                // TODO: when the normalized score of the first suggestion is nearly equals to
-                //       the normalized score of the second suggestion, behave less aggressive.
-                normalizedScore = Utils.calcNormalizedScore(
-                        typedWord, mSuggestions.get(0), mPriorities[0]);
-                if (DBG) {
-                    Log.d(TAG, "Normalized " + typedWord + "," + mSuggestions.get(0) + ","
-                            + mPriorities[0] + ", " + normalizedScore
-                            + "(" + mAutoCorrectionThreshold + ")");
-                }
-                if (normalizedScore >= mAutoCorrectionThreshold) {
-                    if (DBG) {
-                        Log.d(TAG, "Auto corrected by S-threshold.");
-                    }
-                    mHasAutoCorrection = true;
-                }
-            }
         }
+        CharSequence autoText = null;
+        final String typedWordString = typedWord == null ? null : typedWord.toString();
         if (typedWord != null) {
-            mSuggestions.add(0, typedWord.toString());
-        }
-        if (mQuickFixesEnabled) {
-            int i = 0;
-            int max = 6;
-            // Don't autotext the suggestions from the dictionaries
-            if (mCorrectionMode == CORRECTION_BASIC) max = 1;
-            while (i < mSuggestions.size() && i < max) {
-                String suggestedWord = mSuggestions.get(i).toString().toLowerCase();
-                CharSequence autoText =
-                        AutoText.get(suggestedWord, 0, suggestedWord.length(), view);
+            // Apply quick fix only for the typed word.
+            if (mQuickFixesEnabled) {
+                final String lowerCaseTypedWord = typedWordString.toLowerCase();
+                CharSequence tempAutoText =
+                        AutoText.get(lowerCaseTypedWord, 0, lowerCaseTypedWord.length(), view);
                 // Is there an AutoText (also known as Quick Fixes) correction?
-                boolean canAdd = autoText != null;
                 // Capitalize as needed
-                final int autoTextLength = autoText != null ? autoText.length() : 0;
-                if (autoTextLength > 0 && (mIsAllUpperCase || mIsFirstCharCapitalized)) {
-                    int poolSize = mStringPool.size();
-                    StringBuilder sb = poolSize > 0 ? (StringBuilder) mStringPool.remove(
-                            poolSize - 1) : new StringBuilder(getApproxMaxWordLength());
+                if (!TextUtils.isEmpty(tempAutoText)
+                        && (mIsAllUpperCase || mIsFirstCharCapitalized)) {
+                    final int tempAutoTextLength = tempAutoText.length();
+                    final int poolSize = mStringPool.size();
+                    final StringBuilder sb =
+                            poolSize > 0 ? (StringBuilder) mStringPool.remove(poolSize - 1)
+                                    : new StringBuilder(getApproxMaxWordLength());
                     sb.setLength(0);
                     if (mIsAllUpperCase) {
-                        sb.append(autoText.toString().toUpperCase());
+                        sb.append(tempAutoText.toString().toUpperCase());
                     } else if (mIsFirstCharCapitalized) {
-                        sb.append(Character.toUpperCase(autoText.charAt(0)));
-                        if (autoTextLength > 1) {
-                            sb.append(autoText.subSequence(1, autoTextLength));
+                        sb.append(Character.toUpperCase(tempAutoText.charAt(0)));
+                        if (tempAutoTextLength > 1) {
+                            sb.append(tempAutoText.subSequence(1, tempAutoTextLength));
                         }
                     }
-                    autoText = sb.toString();
+                    tempAutoText = sb.toString();
                 }
+                boolean canAdd = tempAutoText != null;
                 // Is that correction already the current prediction (or original word)?
-                canAdd &= !TextUtils.equals(autoText, mSuggestions.get(i));
+                canAdd &= !TextUtils.equals(tempAutoText, typedWord);
                 // Is that correction already the next predicted word?
-                if (canAdd && i + 1 < mSuggestions.size() && mCorrectionMode != CORRECTION_BASIC) {
-                    canAdd &= !TextUtils.equals(autoText, mSuggestions.get(i + 1));
+                if (canAdd && mSuggestions.size() > 0 && mCorrectionMode != CORRECTION_BASIC) {
+                    canAdd &= !TextUtils.equals(tempAutoText, mSuggestions.get(0));
                 }
                 if (canAdd) {
                     if (DBG) {
                         Log.d(TAG, "Auto corrected by AUTOTEXT.");
                     }
-                    mHasAutoCorrection = true;
-                    mSuggestions.add(i + 1, autoText);
-                    i++;
+                    autoText = tempAutoText;
                 }
-                i++;
             }
         }
+
+        mAutoCorrection.updateAutoCorrectionStatus(this, wordComposer, mSuggestions, mPriorities,
+                typedWord, mAutoCorrectionThreshold, mCorrectionMode, autoText);
+
+        if (autoText != null) {
+            mSuggestions.add(0, autoText);
+        }
+
+        if (typedWord != null) {
+            mSuggestions.add(0, typedWordString);
+        }
         removeDupes();
+
         if (DBG) {
+            double normalizedScore = mAutoCorrection.getNormalizedScore();
             ArrayList<SuggestedWords.SuggestedWordInfo> frequencyInfoList =
                     new ArrayList<SuggestedWords.SuggestedWordInfo>();
             frequencyInfoList.add(new SuggestedWords.SuggestedWordInfo("+", false));
@@ -373,9 +358,8 @@ public class Suggest implements Dictionary.WordCallback {
                 frequencyInfoList.add(new SuggestedWords.SuggestedWordInfo("--", false));
             }
             return new SuggestedWords.Builder().addWords(mSuggestions, frequencyInfoList);
-        } else {
-            return new SuggestedWords.Builder().addWords(mSuggestions, null);
         }
+        return new SuggestedWords.Builder().addWords(mSuggestions, null);
     }
 
     private void removeDupes() {
@@ -406,7 +390,7 @@ public class Suggest implements Dictionary.WordCallback {
     }
 
     public boolean hasAutoCorrection() {
-        return mHasAutoCorrection;
+        return mAutoCorrection.hasAutoCorrection();
     }
 
     private static boolean compareCaseInsensitive(final String lowerOriginalWord,
-- 
GitLab