• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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.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 
isEmpty()56     public boolean isEmpty() {
57         return mSuggestedWordInfoList.isEmpty();
58     }
59 
size()60     public int size() {
61         return mSuggestedWordInfoList.size();
62     }
63 
getWord(int pos)64     public String getWord(int pos) {
65         return mSuggestedWordInfoList.get(pos).mWord;
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 (final CompletionInfo info : infos) {
90             if (info == null) continue;
91             final CharSequence text = info.getText();
92             if (null == text) continue;
93             final SuggestedWordInfo suggestedWordInfo = new SuggestedWordInfo(text.toString(),
94                     SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_APP_DEFINED,
95                     Dictionary.TYPE_APPLICATION_DEFINED);
96             result.add(suggestedWordInfo);
97         }
98         return result;
99     }
100 
101     // Should get rid of the first one (what the user typed previously) from suggestions
102     // and replace it with what the user currently typed.
getTypedWordAndPreviousSuggestions( final String typedWord, final SuggestedWords previousSuggestions)103     public static ArrayList<SuggestedWordInfo> getTypedWordAndPreviousSuggestions(
104             final String typedWord, final SuggestedWords previousSuggestions) {
105         final ArrayList<SuggestedWordInfo> suggestionsList = CollectionUtils.newArrayList();
106         final HashSet<String> alreadySeen = CollectionUtils.newHashSet();
107         suggestionsList.add(new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE,
108                 SuggestedWordInfo.KIND_TYPED, Dictionary.TYPE_USER_TYPED));
109         alreadySeen.add(typedWord.toString());
110         final int previousSize = previousSuggestions.size();
111         for (int pos = 1; pos < previousSize; pos++) {
112             final SuggestedWordInfo prevWordInfo = previousSuggestions.getInfo(pos);
113             final String prevWord = prevWordInfo.mWord;
114             // Filter out duplicate suggestion.
115             if (!alreadySeen.contains(prevWord)) {
116                 suggestionsList.add(prevWordInfo);
117                 alreadySeen.add(prevWord);
118             }
119         }
120         return suggestionsList;
121     }
122 
123     public static final class SuggestedWordInfo {
124         public static final int MAX_SCORE = Integer.MAX_VALUE;
125         public static final int KIND_MASK_KIND = 0xFF; // Mask to get only the kind
126         public static final int KIND_TYPED = 0; // What user typed
127         public static final int KIND_CORRECTION = 1; // Simple correction/suggestion
128         public static final int KIND_COMPLETION = 2; // Completion (suggestion with appended chars)
129         public static final int KIND_WHITELIST = 3; // Whitelisted word
130         public static final int KIND_BLACKLIST = 4; // Blacklisted word
131         public static final int KIND_HARDCODED = 5; // Hardcoded suggestion, e.g. punctuation
132         public static final int KIND_APP_DEFINED = 6; // Suggested by the application
133         public static final int KIND_SHORTCUT = 7; // A shortcut
134         public static final int KIND_PREDICTION = 8; // A prediction (== a suggestion with no input)
135         public static final int KIND_RESUMED = 9; // A resumed suggestion (comes from a span)
136 
137         public static final int KIND_MASK_FLAGS = 0xFFFFFF00; // Mask to get the flags
138         public static final int KIND_FLAG_POSSIBLY_OFFENSIVE = 0x80000000;
139         public static final int KIND_FLAG_EXACT_MATCH = 0x40000000;
140 
141         public final String mWord;
142         public final int mScore;
143         public final int mKind; // one of the KIND_* constants above
144         public final int mCodePointCount;
145         public final String mSourceDict;
146         private String mDebugString = "";
147 
SuggestedWordInfo(final String word, final int score, final int kind, final String sourceDict)148         public SuggestedWordInfo(final String word, final int score, final int kind,
149                 final String sourceDict) {
150             mWord = word;
151             mScore = score;
152             mKind = kind;
153             mSourceDict = sourceDict;
154             mCodePointCount = StringUtils.codePointCount(mWord);
155         }
156 
157 
setDebugString(final String str)158         public void setDebugString(final String str) {
159             if (null == str) throw new NullPointerException("Debug info is null");
160             mDebugString = str;
161         }
162 
getDebugString()163         public String getDebugString() {
164             return mDebugString;
165         }
166 
codePointCount()167         public int codePointCount() {
168             return mCodePointCount;
169         }
170 
codePointAt(int i)171         public int codePointAt(int i) {
172             return mWord.codePointAt(i);
173         }
174 
175         @Override
toString()176         public String toString() {
177             if (TextUtils.isEmpty(mDebugString)) {
178                 return mWord;
179             } else {
180                 return mWord + " (" + mDebugString + ")";
181             }
182         }
183 
184         // TODO: Consolidate this method and StringUtils.removeDupes() in the future.
removeDups(ArrayList<SuggestedWordInfo> candidates)185         public static void removeDups(ArrayList<SuggestedWordInfo> candidates) {
186             if (candidates.size() <= 1) {
187                 return;
188             }
189             int i = 1;
190             while (i < candidates.size()) {
191                 final SuggestedWordInfo cur = candidates.get(i);
192                 for (int j = 0; j < i; ++j) {
193                     final SuggestedWordInfo previous = candidates.get(j);
194                     if (cur.mWord.equals(previous.mWord)) {
195                         candidates.remove(cur.mScore < previous.mScore ? i : j);
196                         --i;
197                         break;
198                     }
199                 }
200                 ++i;
201             }
202         }
203     }
204 
205     // SuggestedWords is an immutable object, as much as possible. We must not just remove
206     // words from the member ArrayList as some other parties may expect the object to never change.
207     public SuggestedWords getSuggestedWordsExcludingTypedWord() {
208         final ArrayList<SuggestedWordInfo> newSuggestions = CollectionUtils.newArrayList();
209         for (int i = 0; i < mSuggestedWordInfoList.size(); ++i) {
210             final SuggestedWordInfo info = mSuggestedWordInfoList.get(i);
211             if (SuggestedWordInfo.KIND_TYPED != info.mKind) {
212                 newSuggestions.add(info);
213             }
214         }
215         // We should never autocorrect, so we say the typed word is valid. Also, in this case,
216         // no auto-correction should take place hence willAutoCorrect = false.
217         return new SuggestedWords(newSuggestions, true /* typedWordValid */,
218                 false /* willAutoCorrect */, mIsPunctuationSuggestions, mIsObsoleteSuggestions,
219                 mIsPrediction);
220     }
221 }
222