Home | History | Annotate | Download | only in latin
      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 
     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 
     56     public boolean isEmpty() {
     57         return mSuggestedWordInfoList.isEmpty();
     58     }
     59 
     60     public int size() {
     61         return mSuggestedWordInfoList.size();
     62     }
     63 
     64     public String getWord(int pos) {
     65         return mSuggestedWordInfoList.get(pos).mWord;
     66     }
     67 
     68     public SuggestedWordInfo getInfo(int pos) {
     69         return mSuggestedWordInfoList.get(pos);
     70     }
     71 
     72     public boolean willAutoCorrect() {
     73         return mWillAutoCorrect;
     74     }
     75 
     76     @Override
     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 
     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.
    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 
    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 
    158         public void setDebugString(final String str) {
    159             if (null == str) throw new NullPointerException("Debug info is null");
    160             mDebugString = str;
    161         }
    162 
    163         public String getDebugString() {
    164             return mDebugString;
    165         }
    166 
    167         public int codePointCount() {
    168             return mCodePointCount;
    169         }
    170 
    171         public int codePointAt(int i) {
    172             return mWord.codePointAt(i);
    173         }
    174 
    175         @Override
    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.
    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