aboutsummaryrefslogtreecommitdiffstats
path: root/src/com/android/inputmethod/latin/Suggest.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/inputmethod/latin/Suggest.java')
-rwxr-xr-xsrc/com/android/inputmethod/latin/Suggest.java378
1 files changed, 0 insertions, 378 deletions
diff --git a/src/com/android/inputmethod/latin/Suggest.java b/src/com/android/inputmethod/latin/Suggest.java
deleted file mode 100755
index 712b9cf37..000000000
--- a/src/com/android/inputmethod/latin/Suggest.java
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Copyright (C) 2008-2009 Google Inc.
- *
- * 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.content.Context;
-import android.text.AutoText;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.View;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import com.android.inputmethod.latin.WordComposer;
-
-/**
- * This class loads a dictionary and provides a list of suggestions for a given sequence of
- * characters. This includes corrections and completions.
- * @hide pending API Council Approval
- */
-public class Suggest implements Dictionary.WordCallback {
-
- public static final int CORRECTION_NONE = 0;
- public static final int CORRECTION_BASIC = 1;
- public static final int CORRECTION_FULL = 2;
-
- private static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000;
-
- private BinaryDictionary mMainDict;
-
- private Dictionary mUserDictionary;
-
- private Dictionary mAutoDictionary;
-
- private Dictionary mContactsDictionary;
-
- private int mPrefMaxSuggestions = 12;
-
- private boolean mAutoTextEnabled;
-
- private int[] mPriorities = new int[mPrefMaxSuggestions];
- // Handle predictive correction for only the first 1280 characters for performance reasons
- // If we support scripts that need latin characters beyond that, we should probably use some
- // kind of a sparse array or language specific list with a mapping lookup table.
- // 1280 is the size of the BASE_CHARS array in ExpandableDictionary, which is a basic set of
- // latin characters.
- private int[] mNextLettersFrequencies = new int[1280];
- private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>();
- private ArrayList<CharSequence> mStringPool = new ArrayList<CharSequence>();
- private boolean mHaveCorrection;
- private CharSequence mOriginalWord;
- private String mLowerOriginalWord;
- private boolean mCapitalize;
-
- private int mCorrectionMode = CORRECTION_BASIC;
-
-
- public Suggest(Context context, int dictionaryResId) {
- mMainDict = new BinaryDictionary(context, dictionaryResId);
- for (int i = 0; i < mPrefMaxSuggestions; i++) {
- StringBuilder sb = new StringBuilder(32);
- mStringPool.add(sb);
- }
- }
-
- public void setAutoTextEnabled(boolean enabled) {
- mAutoTextEnabled = enabled;
- }
-
- public int getCorrectionMode() {
- return mCorrectionMode;
- }
-
- public void setCorrectionMode(int mode) {
- mCorrectionMode = mode;
- }
-
- public boolean hasMainDictionary() {
- return mMainDict.getSize() > LARGE_DICTIONARY_THRESHOLD;
- }
-
- /**
- * Sets an optional user dictionary resource to be loaded. The user dictionary is consulted
- * before the main dictionary, if set.
- */
- public void setUserDictionary(Dictionary userDictionary) {
- mUserDictionary = userDictionary;
- }
-
- /**
- * Sets an optional contacts dictionary resource to be loaded.
- */
- public void setContactsDictionary(Dictionary userDictionary) {
- mContactsDictionary = userDictionary;
- }
-
- public void setAutoDictionary(Dictionary autoDictionary) {
- mAutoDictionary = autoDictionary;
- }
-
- /**
- * Number of suggestions to generate from the input key sequence. This has
- * to be a number between 1 and 100 (inclusive).
- * @param maxSuggestions
- * @throws IllegalArgumentException if the number is out of range
- */
- public void setMaxSuggestions(int maxSuggestions) {
- if (maxSuggestions < 1 || maxSuggestions > 100) {
- throw new IllegalArgumentException("maxSuggestions must be between 1 and 100");
- }
- mPrefMaxSuggestions = maxSuggestions;
- mPriorities = new int[mPrefMaxSuggestions];
- collectGarbage();
- while (mStringPool.size() < mPrefMaxSuggestions) {
- StringBuilder sb = new StringBuilder(32);
- mStringPool.add(sb);
- }
- }
-
- private boolean haveSufficientCommonality(String original, CharSequence suggestion) {
- final int originalLength = original.length();
- final int suggestionLength = suggestion.length();
- final int minLength = Math.min(originalLength, suggestionLength);
- if (minLength <= 2) return true;
- int matching = 0;
- int lessMatching = 0; // Count matches if we skip one character
- int i;
- for (i = 0; i < minLength; i++) {
- final char origChar = ExpandableDictionary.toLowerCase(original.charAt(i));
- if (origChar == ExpandableDictionary.toLowerCase(suggestion.charAt(i))) {
- matching++;
- lessMatching++;
- } else if (i + 1 < suggestionLength
- && origChar == ExpandableDictionary.toLowerCase(suggestion.charAt(i + 1))) {
- lessMatching++;
- }
- }
- matching = Math.max(matching, lessMatching);
-
- if (minLength <= 4) {
- return matching >= 2;
- } else {
- return matching > minLength / 2;
- }
- }
-
- /**
- * Returns a list of words that match the list of character codes passed in.
- * This list will be overwritten the next time this function is called.
- * @param a view for retrieving the context for AutoText
- * @param codes the list of codes. Each list item contains an array of character codes
- * in order of probability where the character at index 0 in the array has the highest
- * probability.
- * @return list of suggestions.
- */
- public List<CharSequence> getSuggestions(View view, WordComposer wordComposer,
- boolean includeTypedWordIfValid) {
- mHaveCorrection = false;
- mCapitalize = wordComposer.isCapitalized();
- collectGarbage();
- Arrays.fill(mPriorities, 0);
- Arrays.fill(mNextLettersFrequencies, 0);
-
- // Save a lowercase version of the original word
- mOriginalWord = wordComposer.getTypedWord();
- if (mOriginalWord != null) {
- mOriginalWord = mOriginalWord.toString();
- mLowerOriginalWord = mOriginalWord.toString().toLowerCase();
- } else {
- mLowerOriginalWord = "";
- }
- // Search the dictionary only if there are at least 2 characters
- if (wordComposer.size() > 1) {
- if (mUserDictionary != null || mContactsDictionary != null) {
- if (mUserDictionary != null) {
- mUserDictionary.getWords(wordComposer, this, mNextLettersFrequencies);
- }
- if (mContactsDictionary != null) {
- mContactsDictionary.getWords(wordComposer, this, mNextLettersFrequencies);
- }
-
- if (mSuggestions.size() > 0 && isValidWord(mOriginalWord)
- && mCorrectionMode == CORRECTION_FULL) {
- mHaveCorrection = true;
- }
- }
- mMainDict.getWords(wordComposer, this, mNextLettersFrequencies);
- if (mCorrectionMode == CORRECTION_FULL && mSuggestions.size() > 0) {
- mHaveCorrection = true;
- }
- }
- if (mOriginalWord != null) {
- mSuggestions.add(0, mOriginalWord.toString());
- }
-
- // Check if the first suggestion has a minimum number of characters in common
- if (mCorrectionMode == CORRECTION_FULL && mSuggestions.size() > 1) {
- if (!haveSufficientCommonality(mLowerOriginalWord, mSuggestions.get(1))) {
- mHaveCorrection = false;
- }
- }
-
- if (mAutoTextEnabled) {
- 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);
- // Is there an AutoText correction?
- boolean canAdd = autoText != null;
- // Is that correction already the current prediction (or original word)?
- canAdd &= !TextUtils.equals(autoText, mSuggestions.get(i));
- // 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) {
- mHaveCorrection = true;
- mSuggestions.add(i + 1, autoText);
- i++;
- }
- i++;
- }
- }
-
- removeDupes();
- return mSuggestions;
- }
-
- public int[] getNextLettersFrequencies() {
- return mNextLettersFrequencies;
- }
-
- private void removeDupes() {
- final ArrayList<CharSequence> suggestions = mSuggestions;
- if (suggestions.size() < 2) return;
- int i = 1;
- // Don't cache suggestions.size(), since we may be removing items
- while (i < suggestions.size()) {
- final CharSequence cur = suggestions.get(i);
- // Compare each candidate with each previous candidate
- for (int j = 0; j < i; j++) {
- CharSequence previous = suggestions.get(j);
- if (TextUtils.equals(cur, previous)) {
- removeFromSuggestions(i);
- i--;
- break;
- }
- }
- i++;
- }
- }
-
- private void removeFromSuggestions(int index) {
- CharSequence garbage = mSuggestions.remove(index);
- if (garbage != null && garbage instanceof StringBuilder) {
- mStringPool.add(garbage);
- }
- }
-
- public boolean hasMinimalCorrection() {
- return mHaveCorrection;
- }
-
- private boolean compareCaseInsensitive(final String mLowerOriginalWord,
- final char[] word, final int offset, final int length) {
- final int originalLength = mLowerOriginalWord.length();
- if (originalLength == length && Character.isUpperCase(word[offset])) {
- for (int i = 0; i < originalLength; i++) {
- if (mLowerOriginalWord.charAt(i) != Character.toLowerCase(word[offset+i])) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
-
- public boolean addWord(final char[] word, final int offset, final int length, final int freq) {
- int pos = 0;
- final int[] priorities = mPriorities;
- final int prefMaxSuggestions = mPrefMaxSuggestions;
- // Check if it's the same word, only caps are different
- if (compareCaseInsensitive(mLowerOriginalWord, word, offset, length)) {
- pos = 0;
- } else {
- // Check the last one's priority and bail
- if (priorities[prefMaxSuggestions - 1] >= freq) return true;
- while (pos < prefMaxSuggestions) {
- if (priorities[pos] < freq
- || (priorities[pos] == freq && length < mSuggestions
- .get(pos).length())) {
- break;
- }
- pos++;
- }
- }
-
- if (pos >= prefMaxSuggestions) {
- return true;
- }
- System.arraycopy(priorities, pos, priorities, pos + 1,
- prefMaxSuggestions - pos - 1);
- priorities[pos] = freq;
- int poolSize = mStringPool.size();
- StringBuilder sb = poolSize > 0 ? (StringBuilder) mStringPool.remove(poolSize - 1)
- : new StringBuilder(32);
- sb.setLength(0);
- if (mCapitalize) {
- sb.append(Character.toUpperCase(word[offset]));
- if (length > 1) {
- sb.append(word, offset + 1, length - 1);
- }
- } else {
- sb.append(word, offset, length);
- }
- mSuggestions.add(pos, sb);
- if (mSuggestions.size() > prefMaxSuggestions) {
- CharSequence garbage = mSuggestions.remove(prefMaxSuggestions);
- if (garbage instanceof StringBuilder) {
- mStringPool.add(garbage);
- }
- }
- return true;
- }
-
- public boolean isValidWord(final CharSequence word) {
- if (word == null || word.length() == 0) {
- return false;
- }
- return (mCorrectionMode == CORRECTION_FULL && mMainDict.isValidWord(word))
- || (mCorrectionMode > CORRECTION_NONE &&
- ((mUserDictionary != null && mUserDictionary.isValidWord(word)))
- || (mAutoDictionary != null && mAutoDictionary.isValidWord(word))
- || (mContactsDictionary != null && mContactsDictionary.isValidWord(word)));
- }
-
- private void collectGarbage() {
- int poolSize = mStringPool.size();
- int garbageSize = mSuggestions.size();
- while (poolSize < mPrefMaxSuggestions && garbageSize > 0) {
- CharSequence garbage = mSuggestions.get(garbageSize - 1);
- if (garbage != null && garbage instanceof StringBuilder) {
- mStringPool.add(garbage);
- poolSize++;
- }
- garbageSize--;
- }
- if (poolSize == mPrefMaxSuggestions + 1) {
- Log.w("Suggest", "String pool got too big: " + poolSize);
- }
- mSuggestions.clear();
- }
-
- public void close() {
- if (mMainDict != null) {
- mMainDict.close();
- }
- }
-}