Java 类android.text.style.SuggestionSpan 实例源码

项目:AOSP-Kayboard-7.1.2    文件:SpannableStringUtils.java   
/**
 * Copies the spans from the region <code>start...end</code> in
 * <code>source</code> to the region
 * <code>destoff...destoff+end-start</code> in <code>dest</code>.
 * Spans in <code>source</code> that begin before <code>start</code>
 * or end after <code>end</code> but overlap this range are trimmed
 * as if they began at <code>start</code> or ended at <code>end</code>.
 * Only SuggestionSpans that don't have the SPAN_PARAGRAPH span are copied.
 *
 * This code is almost entirely taken from {@link TextUtils#copySpansFrom}, except for the
 * kind of span that is copied.
 *
 * @throws IndexOutOfBoundsException if any of the copied spans
 * are out of range in <code>dest</code>.
 */
public static void copyNonParagraphSuggestionSpansFrom(Spanned source, int start, int end,
        Spannable dest, int destoff) {
    Object[] spans = source.getSpans(start, end, SuggestionSpan.class);

    for (int i = 0; i < spans.length; i++) {
        int fl = source.getSpanFlags(spans[i]);
        // We don't care about the PARAGRAPH flag in LatinIME code. However, if this flag
        // is set, Spannable#setSpan will throw an exception unless the span is on the edge
        // of a word. But the spans have been split into two by the getText{Before,After}Cursor
        // methods, so after concatenation they may end in the middle of a word.
        // Since we don't use them, we can just remove them and avoid crashing.
        fl &= ~Spanned.SPAN_PARAGRAPH;

        int st = source.getSpanStart(spans[i]);
        int en = source.getSpanEnd(spans[i]);

        if (st < start)
            st = start;
        if (en > end)
            en = end;

        dest.setSpan(spans[i], st - start + destoff, en - start + destoff,
                     fl);
    }
}
项目:Tada    文件:TextView.java   
/**
 * Removes the suggestion spans.
 */
CharSequence removeSuggestionSpans(CharSequence text) {
   if (text instanceof Spanned) {
       Spannable spannable;
       if (text instanceof Spannable) {
           spannable = (Spannable) text;
       } else {
           spannable = new SpannableString(text);
           text = spannable;
       }

       SuggestionSpan[] spans = spannable.getSpans(0, text.length(), SuggestionSpan.class);
       for (int i = 0; i < spans.length; i++) {
           spannable.removeSpan(spans[i]);
       }
   }
   return text;
}
项目:Tada    文件:TextView.java   
void removeAdjacentSuggestionSpans(final int pos) {
    if (!(mText instanceof Editable)) return;
    final Editable text = (Editable) mText;

    final SuggestionSpan[] spans = text.getSpans(pos, pos, SuggestionSpan.class);
    final int length = spans.length;
    for (int i = 0; i < length; i++) {
        final int spanStart = text.getSpanStart(spans[i]);
        final int spanEnd = text.getSpanEnd(spans[i]);
        if (spanEnd == pos || spanStart == pos) {
            if (SpellChecker.haveWordBoundariesChanged(text, pos, pos, spanStart, spanEnd)) {
                text.removeSpan(spans[i]);
            }
        }
    }
}
项目:spanner    文件:Spans.java   
/**
 * @see android.text.style.SuggestionSpan
 */
public static Span suggestion(@NonNull final Context context, @NonNull final String[] suggestions, final int flags) {
    return new Span(new SpanBuilder() {
        @Override
        public Object build() {
            return new SuggestionSpan(context, suggestions, flags);
        }
    });
}
项目:spanner    文件:Spans.java   
/**
 * @see android.text.style.SuggestionSpan
 */
public static Span suggestion(@NonNull final Locale locale, @NonNull final String[] suggestions, final int flags) {
    return new Span(new SpanBuilder() {
        @Override
        public Object build() {
            return new SuggestionSpan(locale, suggestions, flags);
        }
    });
}
项目:spanner    文件:Spans.java   
/**
 * @see android.text.style.SuggestionSpan
 */
public static Span suggestion(@NonNull final Context context, @NonNull final Locale locale, @NonNull final String[] suggestions, final int flags, @NonNull final Class<?> notificationTargetClass) {
    return new Span(new SpanBuilder() {
        @Override
        public Object build() {
            return new SuggestionSpan(context, locale, suggestions, flags, notificationTargetClass);
        }
    });
}
项目:AOSP-Kayboard-7.1.2    文件:SuggestionSpanUtils.java   
@UsedForTesting
public static CharSequence getTextWithAutoCorrectionIndicatorUnderline(
        final Context context, final String text, @Nonnull final Locale locale) {
    if (TextUtils.isEmpty(text) || OBJ_FLAG_AUTO_CORRECTION == null) {
        return text;
    }
    final Spannable spannable = new SpannableString(text);
    final SuggestionSpan suggestionSpan = new SuggestionSpan(context, locale,
            new String[] {} /* suggestions */, OBJ_FLAG_AUTO_CORRECTION, null);
    spannable.setSpan(suggestionSpan, 0, text.length(),
            Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
    return spannable;
}
项目:AOSP-Kayboard-7.1.2    文件:SuggestionSpanUtils.java   
@UsedForTesting
public static CharSequence getTextWithSuggestionSpan(final Context context,
        final String pickedWord, final SuggestedWords suggestedWords, final Locale locale) {
    if (TextUtils.isEmpty(pickedWord) || suggestedWords.isEmpty()
            || suggestedWords.isPrediction() || suggestedWords.isPunctuationSuggestions()) {
        return pickedWord;
    }

    final ArrayList<String> suggestionsList = new ArrayList<>();
    for (int i = 0; i < suggestedWords.size(); ++i) {
        if (suggestionsList.size() >= SuggestionSpan.SUGGESTIONS_MAX_SIZE) {
            break;
        }
        final SuggestedWordInfo info = suggestedWords.getInfo(i);
        if (info.isKindOf(SuggestedWordInfo.KIND_PREDICTION)) {
            continue;
        }
        final String word = suggestedWords.getWord(i);
        if (!TextUtils.equals(pickedWord, word)) {
            suggestionsList.add(word.toString());
        }
    }
    final SuggestionSpan suggestionSpan = new SuggestionSpan(context, locale,
            suggestionsList.toArray(new String[suggestionsList.size()]), 0 /* flags */, null);
    final Spannable spannable = new SpannableString(pickedWord);
    spannable.setSpan(suggestionSpan, 0, pickedWord.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    return spannable;
}
项目:AOSP-Kayboard-7.1.2    文件:SuggestionSpanUtils.java   
/**
 * Returns first {@link Locale} found in the given array of {@link SuggestionSpan}.
 * @param suggestionSpans the array of {@link SuggestionSpan} to be examined.
 * @return the first {@link Locale} found in {@code suggestionSpans}. {@code null} when not
 * found.
 */
@UsedForTesting
@Nullable
public static Locale findFirstLocaleFromSuggestionSpans(
        final SuggestionSpan[] suggestionSpans) {
    for (final SuggestionSpan suggestionSpan : suggestionSpans) {
        final String localeString = suggestionSpan.getLocale();
        if (TextUtils.isEmpty(localeString)) {
            continue;
        }
        return LocaleUtils.constructLocaleFromString(localeString);
    }
    return null;
}
项目:Tada    文件:TextView.java   
void removeMisspelledSpans(Spannable spannable) {
    SuggestionSpan[] suggestionSpans = spannable.getSpans(0, spannable.length(),
            SuggestionSpan.class);
    for (int i = 0; i < suggestionSpans.length; i++) {
        int flags = suggestionSpans[i].getFlags();
        if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
                && (flags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
            spannable.removeSpan(suggestionSpans[i]);
        }
    }
}
项目:Tada    文件:TextView.java   
private void sendBeforeTextChanged(CharSequence text, int start, int before, int after) {
    if (mListeners != null) {
        final ArrayList<TextWatcher> list = mListeners;
        final int count = list.size();
        for (int i = 0; i < count; i++) {
            list.get(i).beforeTextChanged(text, start, before, after);
        }
    }

    // The spans that are inside or intersect the modified region no longer make sense
    removeIntersectingNonAdjacentSpans(start, start + before, SpellCheckSpan.class);
    removeIntersectingNonAdjacentSpans(start, start + before, SuggestionSpan.class);
}
项目:android-kioskime    文件:SuggestionSpanPickedNotificationReceiver.java   
@Override
public void onReceive(Context context, Intent intent) {
    if (SuggestionSpan.ACTION_SUGGESTION_PICKED.equals(intent.getAction())) {
        if (DBG) {
            final String before = intent.getStringExtra(
                    SuggestionSpan.SUGGESTION_SPAN_PICKED_BEFORE);
            final String after = intent.getStringExtra(
                    SuggestionSpan.SUGGESTION_SPAN_PICKED_AFTER);
            Log.d(TAG, "Received notification picked: " + before + "," + after);
        }
    }
}
项目:android-kioskime    文件:SuggestionSpanUtils.java   
public static CharSequence getTextWithAutoCorrectionIndicatorUnderline(
        final Context context, final String text) {
    if (TextUtils.isEmpty(text) || OBJ_FLAG_AUTO_CORRECTION == null) {
        return text;
    }
    final Spannable spannable = new SpannableString(text);
    final SuggestionSpan suggestionSpan = new SuggestionSpan(context, null /* locale */,
            new String[] {} /* suggestions */, (int)OBJ_FLAG_AUTO_CORRECTION,
            SuggestionSpanPickedNotificationReceiver.class);
    spannable.setSpan(suggestionSpan, 0, text.length(),
            Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
    return spannable;
}
项目:android-kioskime    文件:SuggestionSpanUtils.java   
public static CharSequence getTextWithSuggestionSpan(final Context context,
        final String pickedWord, final SuggestedWords suggestedWords,
        final boolean dictionaryAvailable) {
    if (!dictionaryAvailable || TextUtils.isEmpty(pickedWord) || suggestedWords.isEmpty()
            || suggestedWords.mIsPrediction || suggestedWords.mIsPunctuationSuggestions) {
        return pickedWord;
    }

    final Spannable spannable = new SpannableString(pickedWord);
    final ArrayList<String> suggestionsList = CollectionUtils.newArrayList();
    for (int i = 0; i < suggestedWords.size(); ++i) {
        if (suggestionsList.size() >= SuggestionSpan.SUGGESTIONS_MAX_SIZE) {
            break;
        }
        final String word = suggestedWords.getWord(i);
        if (!TextUtils.equals(pickedWord, word)) {
            suggestionsList.add(word.toString());
        }
    }

    // TODO: We should avoid adding suggestion span candidates that came from the bigram
    // prediction.
    final SuggestionSpan suggestionSpan = new SuggestionSpan(context, null /* locale */,
            suggestionsList.toArray(new String[suggestionsList.size()]), 0 /* flags */,
            SuggestionSpanPickedNotificationReceiver.class);
    spannable.setSpan(suggestionSpan, 0, pickedWord.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    return spannable;
}
项目:AOSP-Kayboard-7.1.2    文件:TextRange.java   
/**
 * Gets the suggestion spans that are put squarely on the word, with the exact start
 * and end of the span matching the boundaries of the word.
 * @return the list of spans.
 */
public SuggestionSpan[] getSuggestionSpansAtWord() {
    if (!(mTextAtCursor instanceof Spanned && mWord instanceof Spanned)) {
        return new SuggestionSpan[0];
    }
    final Spanned text = (Spanned)mTextAtCursor;
    // Note: it's fine to pass indices negative or greater than the length of the string
    // to the #getSpans() method. The reason we need to get from -1 to +1 is that, the
    // spans were cut at the cursor position, and #getSpans(start, end) does not return
    // spans that end at `start' or begin at `end'. Consider the following case:
    //              this| is          (The | symbolizes the cursor position
    //              ---- ---
    // In this case, the cursor is in position 4, so the 0~7 span has been split into
    // a 0~4 part and a 4~7 part.
    // If we called #getSpans(0, 4) in this case, we would only get the part from 0 to 4
    // of the span, and not the part from 4 to 7, so we would not realize the span actually
    // extends from 0 to 7. But if we call #getSpans(-1, 5) we'll get both the 0~4 and
    // the 4~7 spans and we can merge them accordingly.
    // Any span starting more than 1 char away from the word boundaries in any direction
    // does not touch the word, so we don't need to consider it. That's why requesting
    // -1 ~ +1 is enough.
    // Of course this is only relevant if the cursor is at one end of the word. If it's
    // in the middle, the -1 and +1 are not necessary, but they are harmless.
    final SuggestionSpan[] spans = text.getSpans(mWordAtCursorStartIndex - 1,
            mWordAtCursorEndIndex + 1, SuggestionSpan.class);
    int readIndex = 0;
    int writeIndex = 0;
    for (; readIndex < spans.length; ++readIndex) {
        final SuggestionSpan span = spans[readIndex];
        // The span may be null, as we null them when we find duplicates. Cf a few lines
        // down.
        if (null == span) continue;
        // Tentative span start and end. This may be modified later if we realize the
        // same span is also applied to other parts of the string.
        int spanStart = text.getSpanStart(span);
        int spanEnd = text.getSpanEnd(span);
        for (int i = readIndex + 1; i < spans.length; ++i) {
            if (span.equals(spans[i])) {
                // We found the same span somewhere else. Read the new extent of this
                // span, and adjust our values accordingly.
                spanStart = Math.min(spanStart, text.getSpanStart(spans[i]));
                spanEnd = Math.max(spanEnd, text.getSpanEnd(spans[i]));
                // ...and mark the span as processed.
                spans[i] = null;
            }
        }
        if (spanStart == mWordAtCursorStartIndex && spanEnd == mWordAtCursorEndIndex) {
            // If the span does not start and stop here, ignore it. It probably extends
            // past the start or end of the word, as happens in missing space correction
            // or EasyEditSpans put by voice input.
            spans[writeIndex++] = spans[readIndex];
        }
    }
    return writeIndex == readIndex ? spans : Arrays.copyOfRange(spans, 0, writeIndex);
}
项目:android-kioskime    文件:LatinIME.java   
/**
 * Check if the cursor is touching a word. If so, restart suggestions on this word, else
 * do nothing.
 */
private void restartSuggestionsOnWordTouchedByCursor() {
    // HACK: We may want to special-case some apps that exhibit bad behavior in case of
    // recorrection. This is a temporary, stopgap measure that will be removed later.
    // TODO: remove this.
    if (mAppWorkAroundsUtils.isBrokenByRecorrection()) return;
    // If the cursor is not touching a word, or if there is a selection, return right away.
    if (mLastSelectionStart != mLastSelectionEnd) return;
    // If we don't know the cursor location, return.
    if (mLastSelectionStart < 0) return;
    if (!mConnection.isCursorTouchingWord(mSettings.getCurrent())) return;
    final Range range = mConnection.getWordRangeAtCursor(mSettings.getWordSeparators(),
            0 /* additionalPrecedingWordsCount */);
    if (null == range) return; // Happens if we don't have an input connection at all
    // If for some strange reason (editor bug or so) we measure the text before the cursor as
    // longer than what the entire text is supposed to be, the safe thing to do is bail out.
    if (range.mCharsBefore > mLastSelectionStart) return;
    final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
    final String typedWord = range.mWord.toString();
    if (range.mWord instanceof SpannableString) {
        final SpannableString spannableString = (SpannableString)range.mWord;
        int i = 0;
        for (Object object : spannableString.getSpans(0, spannableString.length(),
                SuggestionSpan.class)) {
            SuggestionSpan span = (SuggestionSpan)object;
            for (String s : span.getSuggestions()) {
                ++i;
                if (!TextUtils.equals(s, typedWord)) {
                    suggestions.add(new SuggestedWordInfo(s,
                            SuggestionStripView.MAX_SUGGESTIONS - i,
                            SuggestedWordInfo.KIND_RESUMED, Dictionary.TYPE_RESUMED));
                }
            }
        }
    }
    mWordComposer.setComposingWord(typedWord, mKeyboardSwitcher.getKeyboard());
    mWordComposer.setCursorPositionWithinWord(range.mCharsBefore);
    mConnection.setComposingRegion(mLastSelectionStart - range.mCharsBefore,
            mLastSelectionEnd + range.mCharsAfter);
    final SuggestedWords suggestedWords;
    if (suggestions.isEmpty()) {
        // We come here if there weren't any suggestion spans on this word. We will try to
        // compute suggestions for it instead.
        final SuggestedWords suggestedWordsIncludingTypedWord =
                getSuggestedWords(Suggest.SESSION_TYPING);
        if (suggestedWordsIncludingTypedWord.size() > 1) {
            // We were able to compute new suggestions for this word.
            // Remove the typed word, since we don't want to display it in this case.
            // The #getSuggestedWordsExcludingTypedWord() method sets willAutoCorrect to false.
            suggestedWords =
                    suggestedWordsIncludingTypedWord.getSuggestedWordsExcludingTypedWord();
        } else {
            // No saved suggestions, and we were unable to compute any good one either.
            // Rather than displaying an empty suggestion strip, we'll display the original
            // word alone in the middle.
            // Since there is only one word, willAutoCorrect is false.
            suggestedWords = suggestedWordsIncludingTypedWord;
        }
    } else {
        // We found suggestion spans in the word. We'll create the SuggestedWords out of
        // them, and make willAutoCorrect false.
        suggestedWords = new SuggestedWords(suggestions,
                true /* typedWordValid */, false /* willAutoCorrect */,
                false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */,
                false /* isPrediction */);
    }

    // Note that it's very important here that suggestedWords.mWillAutoCorrect is false.
    // We never want to auto-correct on a resumed suggestion. Please refer to the three
    // places above where suggestedWords is affected. We also need to reset
    // mIsAutoCorrectionIndicatorOn to avoid showSuggestionStrip touching the text to adapt it.
    // TODO: remove mIsAutoCorrectionIndicator on (see comment on definition)
    mIsAutoCorrectionIndicatorOn = false;
    showSuggestionStrip(suggestedWords, typedWord);
}