Search in sources :

Example 46 with SuggestionSpan

use of android.text.style.SuggestionSpan in project android_packages_inputmethods_LatinIME by CyanogenMod.

the class SpannableStringUtilsTests method testConcatWithSuggestionSpansOnly.

public void testConcatWithSuggestionSpansOnly() {
    SpannableStringBuilder s = new SpannableStringBuilder("test string\ntest string\n" + "test string\ntest string\ntest string\ntest string\ntest string\ntest string\n" + "test string\ntest string\n");
    final int N = 10;
    for (int i = 0; i < N; ++i) {
        // Put a PARAGRAPH-flagged span that should not be found in the result.
        s.setSpan(new SuggestionSpan(getContext(), new String[] { "" + i }, Spanned.SPAN_PARAGRAPH), i * 12, i * 12 + 12, Spanned.SPAN_PARAGRAPH);
        // Put a normal suggestion span that should be found in the result.
        s.setSpan(new SuggestionSpan(getContext(), new String[] { "" + i }, 0), i, i * 2, 0);
        // Put a URL span than should not be found in the result.
        s.setSpan(new URLSpan("http://a"), i, i * 2, 0);
    }
    final CharSequence a = s.subSequence(0, 15);
    final CharSequence b = s.subSequence(15, s.length());
    final Spanned result = (Spanned) SpannableStringUtils.concatWithNonParagraphSuggestionSpansOnly(a, b);
    Object[] spans = result.getSpans(0, result.length(), SuggestionSpan.class);
    for (int i = 0; i < spans.length; i++) {
        final int flags = result.getSpanFlags(spans[i]);
        assertEquals("Should not find a span with PARAGRAPH flag", flags & Spanned.SPAN_PARAGRAPH, 0);
        assertTrue("Should be a SuggestionSpan", spans[i] instanceof SuggestionSpan);
    }
}
Also used : SuggestionSpan(android.text.style.SuggestionSpan) SpannedString(android.text.SpannedString) SpannableString(android.text.SpannableString) URLSpan(android.text.style.URLSpan) Spanned(android.text.Spanned) SpannableStringBuilder(android.text.SpannableStringBuilder)

Example 47 with SuggestionSpan

use of android.text.style.SuggestionSpan in project android_packages_inputmethods_LatinIME by CyanogenMod.

the class TextRange method getSuggestionSpansAtWord.

/**
 * 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];
        // 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);
}
Also used : SuggestionSpan(android.text.style.SuggestionSpan) Spanned(android.text.Spanned)

Example 48 with SuggestionSpan

use of android.text.style.SuggestionSpan in project platform_frameworks_base by android.

the class Editor method replaceWithSuggestion.

private void replaceWithSuggestion(@NonNull final SuggestionInfo suggestionInfo) {
    final SuggestionSpan targetSuggestionSpan = findEquivalentSuggestionSpan(suggestionInfo.mSuggestionSpanInfo);
    if (targetSuggestionSpan == null) {
        // Span has been removed
        return;
    }
    final Editable editable = (Editable) mTextView.getText();
    final int spanStart = editable.getSpanStart(targetSuggestionSpan);
    final int spanEnd = editable.getSpanEnd(targetSuggestionSpan);
    if (spanStart < 0 || spanEnd <= spanStart) {
        // Span has been removed
        return;
    }
    final String originalText = TextUtils.substring(editable, spanStart, spanEnd);
    // SuggestionSpans are removed by replace: save them before
    SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd, SuggestionSpan.class);
    final int length = suggestionSpans.length;
    int[] suggestionSpansStarts = new int[length];
    int[] suggestionSpansEnds = new int[length];
    int[] suggestionSpansFlags = new int[length];
    for (int i = 0; i < length; i++) {
        final SuggestionSpan suggestionSpan = suggestionSpans[i];
        suggestionSpansStarts[i] = editable.getSpanStart(suggestionSpan);
        suggestionSpansEnds[i] = editable.getSpanEnd(suggestionSpan);
        suggestionSpansFlags[i] = editable.getSpanFlags(suggestionSpan);
        // Remove potential misspelled flags
        int suggestionSpanFlags = suggestionSpan.getFlags();
        if ((suggestionSpanFlags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
            suggestionSpanFlags &= ~SuggestionSpan.FLAG_MISSPELLED;
            suggestionSpanFlags &= ~SuggestionSpan.FLAG_EASY_CORRECT;
            suggestionSpan.setFlags(suggestionSpanFlags);
        }
    }
    // Notify source IME of the suggestion pick. Do this before swapping texts.
    targetSuggestionSpan.notifySelection(mTextView.getContext(), originalText, suggestionInfo.mSuggestionIndex);
    // Swap text content between actual text and Suggestion span
    final int suggestionStart = suggestionInfo.mSuggestionStart;
    final int suggestionEnd = suggestionInfo.mSuggestionEnd;
    final String suggestion = suggestionInfo.mText.subSequence(suggestionStart, suggestionEnd).toString();
    mTextView.replaceText_internal(spanStart, spanEnd, suggestion);
    String[] suggestions = targetSuggestionSpan.getSuggestions();
    suggestions[suggestionInfo.mSuggestionIndex] = originalText;
    // Restore previous SuggestionSpans
    final int lengthDelta = suggestion.length() - (spanEnd - spanStart);
    for (int i = 0; i < length; i++) {
        // way to assign them a valid range after replacement
        if (suggestionSpansStarts[i] <= spanStart && suggestionSpansEnds[i] >= spanEnd) {
            mTextView.setSpan_internal(suggestionSpans[i], suggestionSpansStarts[i], suggestionSpansEnds[i] + lengthDelta, suggestionSpansFlags[i]);
        }
    }
    // Move cursor at the end of the replaced word
    final int newCursorPosition = spanEnd + lengthDelta;
    mTextView.setCursorPosition_internal(newCursorPosition, newCursorPosition);
}
Also used : Editable(android.text.Editable) SuggestionSpan(android.text.style.SuggestionSpan) Paint(android.graphics.Paint)

Example 49 with SuggestionSpan

use of android.text.style.SuggestionSpan in project platform_frameworks_base by android.

the class Editor method findEquivalentSuggestionSpan.

@Nullable
private SuggestionSpan findEquivalentSuggestionSpan(@NonNull SuggestionSpanInfo suggestionSpanInfo) {
    final Editable editable = (Editable) mTextView.getText();
    if (editable.getSpanStart(suggestionSpanInfo.mSuggestionSpan) >= 0) {
        // Exactly same span is found.
        return suggestionSpanInfo.mSuggestionSpan;
    }
    // Suggestion span couldn't be found. Try to find a suggestion span that has the same
    // contents.
    final SuggestionSpan[] suggestionSpans = editable.getSpans(suggestionSpanInfo.mSpanStart, suggestionSpanInfo.mSpanEnd, SuggestionSpan.class);
    for (final SuggestionSpan suggestionSpan : suggestionSpans) {
        final int start = editable.getSpanStart(suggestionSpan);
        if (start != suggestionSpanInfo.mSpanStart) {
            continue;
        }
        final int end = editable.getSpanEnd(suggestionSpan);
        if (end != suggestionSpanInfo.mSpanEnd) {
            continue;
        }
        if (suggestionSpan.equals(suggestionSpanInfo.mSuggestionSpan)) {
            return suggestionSpan;
        }
    }
    return null;
}
Also used : Editable(android.text.Editable) SuggestionSpan(android.text.style.SuggestionSpan) Paint(android.graphics.Paint) Nullable(android.annotation.Nullable)

Example 50 with SuggestionSpan

use of android.text.style.SuggestionSpan in project platform_frameworks_base by android.

the class Editor method shouldOfferToShowSuggestions.

/**
     * @return <code>true</code> if it's reasonable to offer to show suggestions depending on
     * the current cursor position or selection range. This method is consistent with the
     * method to show suggestions {@link SuggestionsPopupWindow#updateSuggestions}.
     */
private boolean shouldOfferToShowSuggestions() {
    CharSequence text = mTextView.getText();
    if (!(text instanceof Spannable))
        return false;
    final Spannable spannable = (Spannable) text;
    final int selectionStart = mTextView.getSelectionStart();
    final int selectionEnd = mTextView.getSelectionEnd();
    final SuggestionSpan[] suggestionSpans = spannable.getSpans(selectionStart, selectionEnd, SuggestionSpan.class);
    if (suggestionSpans.length == 0) {
        return false;
    }
    if (selectionStart == selectionEnd) {
        // Spans overlap the cursor.
        for (int i = 0; i < suggestionSpans.length; i++) {
            if (suggestionSpans[i].getSuggestions().length > 0) {
                return true;
            }
        }
        return false;
    }
    int minSpanStart = mTextView.getText().length();
    int maxSpanEnd = 0;
    int unionOfSpansCoveringSelectionStartStart = mTextView.getText().length();
    int unionOfSpansCoveringSelectionStartEnd = 0;
    boolean hasValidSuggestions = false;
    for (int i = 0; i < suggestionSpans.length; i++) {
        final int spanStart = spannable.getSpanStart(suggestionSpans[i]);
        final int spanEnd = spannable.getSpanEnd(suggestionSpans[i]);
        minSpanStart = Math.min(minSpanStart, spanStart);
        maxSpanEnd = Math.max(maxSpanEnd, spanEnd);
        if (selectionStart < spanStart || selectionStart > spanEnd) {
            // The span doesn't cover the current selection start point.
            continue;
        }
        hasValidSuggestions = hasValidSuggestions || suggestionSpans[i].getSuggestions().length > 0;
        unionOfSpansCoveringSelectionStartStart = Math.min(unionOfSpansCoveringSelectionStartStart, spanStart);
        unionOfSpansCoveringSelectionStartEnd = Math.max(unionOfSpansCoveringSelectionStartEnd, spanEnd);
    }
    if (!hasValidSuggestions) {
        return false;
    }
    if (unionOfSpansCoveringSelectionStartStart >= unionOfSpansCoveringSelectionStartEnd) {
        // No spans cover the selection start point.
        return false;
    }
    if (minSpanStart < unionOfSpansCoveringSelectionStartStart || maxSpanEnd > unionOfSpansCoveringSelectionStartEnd) {
        // to show suggestions as it's confusing.
        return false;
    }
    return true;
}
Also used : SuggestionSpan(android.text.style.SuggestionSpan) Spannable(android.text.Spannable) Paint(android.graphics.Paint)

Aggregations

SuggestionSpan (android.text.style.SuggestionSpan)114 Paint (android.graphics.Paint)43 SmallTest (android.test.suitebuilder.annotation.SmallTest)35 Spannable (android.text.Spannable)29 Spanned (android.text.Spanned)24 Editable (android.text.Editable)21 TextPaint (android.text.TextPaint)21 SpannableString (android.text.SpannableString)14 View (android.view.View)10 SpannableStringBuilder (android.text.SpannableStringBuilder)7 SpellCheckSpan (android.text.style.SpellCheckSpan)7 Nullable (android.annotation.Nullable)5 TypedArray (android.content.res.TypedArray)5 Espresso.onView (android.support.test.espresso.Espresso.onView)5 NoMatchingViewException (android.support.test.espresso.NoMatchingViewException)5 ViewAssertion (android.support.test.espresso.ViewAssertion)5 RootMatchers.withDecorView (android.support.test.espresso.matcher.RootMatchers.withDecorView)5 BackgroundColorSpan (android.text.style.BackgroundColorSpan)5 ForegroundColorSpan (android.text.style.ForegroundColorSpan)5 ImageSpan (android.text.style.ImageSpan)5