1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package com.android.inputmethod.latin; 18 19 import android.text.TextUtils; 20 import android.view.inputmethod.CompletionInfo; 21 22 import java.util.ArrayList; 23 import java.util.Arrays; 24 import java.util.HashSet; 25 26 public final class SuggestedWords { 27 private static final ArrayList<SuggestedWordInfo> EMPTY_WORD_INFO_LIST = 28 CollectionUtils.newArrayList(0); 29 public static final SuggestedWords EMPTY = new SuggestedWords( 30 EMPTY_WORD_INFO_LIST, false, false, false, false, false); 31 32 public final boolean mTypedWordValid; 33 // Note: this INCLUDES cases where the word will auto-correct to itself. A good definition 34 // of what this flag means would be "the top suggestion is strong enough to auto-correct", 35 // whether this exactly matches the user entry or not. 36 public final boolean mWillAutoCorrect; 37 public final boolean mIsPunctuationSuggestions; 38 public final boolean mIsObsoleteSuggestions; 39 public final boolean mIsPrediction; 40 private final ArrayList<SuggestedWordInfo> mSuggestedWordInfoList; 41 SuggestedWords(final ArrayList<SuggestedWordInfo> suggestedWordInfoList, final boolean typedWordValid, final boolean willAutoCorrect, final boolean isPunctuationSuggestions, final boolean isObsoleteSuggestions, final boolean isPrediction)42 public SuggestedWords(final ArrayList<SuggestedWordInfo> suggestedWordInfoList, 43 final boolean typedWordValid, 44 final boolean willAutoCorrect, 45 final boolean isPunctuationSuggestions, 46 final boolean isObsoleteSuggestions, 47 final boolean isPrediction) { 48 mSuggestedWordInfoList = suggestedWordInfoList; 49 mTypedWordValid = typedWordValid; 50 mWillAutoCorrect = willAutoCorrect; 51 mIsPunctuationSuggestions = isPunctuationSuggestions; 52 mIsObsoleteSuggestions = isObsoleteSuggestions; 53 mIsPrediction = isPrediction; 54 } 55 size()56 public int size() { 57 return mSuggestedWordInfoList.size(); 58 } 59 getWord(int pos)60 public String getWord(int pos) { 61 return mSuggestedWordInfoList.get(pos).mWord; 62 } 63 getWordInfo(int pos)64 public SuggestedWordInfo getWordInfo(int pos) { 65 return mSuggestedWordInfoList.get(pos); 66 } 67 getInfo(int pos)68 public SuggestedWordInfo getInfo(int pos) { 69 return mSuggestedWordInfoList.get(pos); 70 } 71 willAutoCorrect()72 public boolean willAutoCorrect() { 73 return mWillAutoCorrect; 74 } 75 76 @Override toString()77 public String toString() { 78 // Pretty-print method to help debug 79 return "SuggestedWords:" 80 + " mTypedWordValid=" + mTypedWordValid 81 + " mWillAutoCorrect=" + mWillAutoCorrect 82 + " mIsPunctuationSuggestions=" + mIsPunctuationSuggestions 83 + " words=" + Arrays.toString(mSuggestedWordInfoList.toArray()); 84 } 85 getFromApplicationSpecifiedCompletions( final CompletionInfo[] infos)86 public static ArrayList<SuggestedWordInfo> getFromApplicationSpecifiedCompletions( 87 final CompletionInfo[] infos) { 88 final ArrayList<SuggestedWordInfo> result = CollectionUtils.newArrayList(); 89 for (CompletionInfo info : infos) { 90 if (null != info && info.getText() != null) { 91 result.add(new SuggestedWordInfo(info.getText(), SuggestedWordInfo.MAX_SCORE, 92 SuggestedWordInfo.KIND_APP_DEFINED, Dictionary.TYPE_APPLICATION_DEFINED)); 93 } 94 } 95 return result; 96 } 97 98 // Should get rid of the first one (what the user typed previously) from suggestions 99 // and replace it with what the user currently typed. getTypedWordAndPreviousSuggestions( final CharSequence typedWord, final SuggestedWords previousSuggestions)100 public static ArrayList<SuggestedWordInfo> getTypedWordAndPreviousSuggestions( 101 final CharSequence typedWord, final SuggestedWords previousSuggestions) { 102 final ArrayList<SuggestedWordInfo> suggestionsList = CollectionUtils.newArrayList(); 103 final HashSet<String> alreadySeen = CollectionUtils.newHashSet(); 104 suggestionsList.add(new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE, 105 SuggestedWordInfo.KIND_TYPED, Dictionary.TYPE_USER_TYPED)); 106 alreadySeen.add(typedWord.toString()); 107 final int previousSize = previousSuggestions.size(); 108 for (int pos = 1; pos < previousSize; pos++) { 109 final SuggestedWordInfo prevWordInfo = previousSuggestions.getWordInfo(pos); 110 final String prevWord = prevWordInfo.mWord.toString(); 111 // Filter out duplicate suggestion. 112 if (!alreadySeen.contains(prevWord)) { 113 suggestionsList.add(prevWordInfo); 114 alreadySeen.add(prevWord); 115 } 116 } 117 return suggestionsList; 118 } 119 120 public static final class SuggestedWordInfo { 121 public static final int MAX_SCORE = Integer.MAX_VALUE; 122 public static final int KIND_TYPED = 0; // What user typed 123 public static final int KIND_CORRECTION = 1; // Simple correction/suggestion 124 public static final int KIND_COMPLETION = 2; // Completion (suggestion with appended chars) 125 public static final int KIND_WHITELIST = 3; // Whitelisted word 126 public static final int KIND_BLACKLIST = 4; // Blacklisted word 127 public static final int KIND_HARDCODED = 5; // Hardcoded suggestion, e.g. punctuation 128 public static final int KIND_APP_DEFINED = 6; // Suggested by the application 129 public static final int KIND_SHORTCUT = 7; // A shortcut 130 public static final int KIND_PREDICTION = 8; // A prediction (== a suggestion with no input) 131 public final String mWord; 132 public final int mScore; 133 public final int mKind; // one of the KIND_* constants above 134 public final int mCodePointCount; 135 public final String mSourceDict; 136 private String mDebugString = ""; 137 SuggestedWordInfo(final CharSequence word, final int score, final int kind, final String sourceDict)138 public SuggestedWordInfo(final CharSequence word, final int score, final int kind, 139 final String sourceDict) { 140 mWord = word.toString(); 141 mScore = score; 142 mKind = kind; 143 mSourceDict = sourceDict; 144 mCodePointCount = StringUtils.codePointCount(mWord); 145 } 146 147 setDebugString(String str)148 public void setDebugString(String str) { 149 if (null == str) throw new NullPointerException("Debug info is null"); 150 mDebugString = str; 151 } 152 getDebugString()153 public String getDebugString() { 154 return mDebugString; 155 } 156 codePointCount()157 public int codePointCount() { 158 return mCodePointCount; 159 } 160 codePointAt(int i)161 public int codePointAt(int i) { 162 return mWord.codePointAt(i); 163 } 164 165 @Override toString()166 public String toString() { 167 if (TextUtils.isEmpty(mDebugString)) { 168 return mWord; 169 } else { 170 return mWord + " (" + mDebugString.toString() + ")"; 171 } 172 } 173 174 // TODO: Consolidate this method and StringUtils.removeDupes() in the future. removeDups(ArrayList<SuggestedWordInfo> candidates)175 public static void removeDups(ArrayList<SuggestedWordInfo> candidates) { 176 if (candidates.size() <= 1) { 177 return; 178 } 179 int i = 1; 180 while (i < candidates.size()) { 181 final SuggestedWordInfo cur = candidates.get(i); 182 for (int j = 0; j < i; ++j) { 183 final SuggestedWordInfo previous = candidates.get(j); 184 if (cur.mWord.equals(previous.mWord)) { 185 candidates.remove(cur.mScore < previous.mScore ? i : j); 186 --i; 187 break; 188 } 189 } 190 ++i; 191 } 192 } 193 } 194 } 195