SpellChecker.java revision d6e3494421dff2a091f1011e5266b280b2109843
16435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne// Copyright 2011 Google Inc. All Rights Reserved.
26435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
36435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunnepackage android.widget;
46435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
56435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunneimport android.content.Context;
66435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunneimport android.text.Editable;
76435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunneimport android.text.Selection;
86435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunneimport android.text.Spanned;
96435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunneimport android.text.style.SpellCheckSpan;
106435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunneimport android.text.style.SuggestionSpan;
116435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunneimport android.util.Log;
126435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunneimport android.view.textservice.SpellCheckerSession;
136435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunneimport android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener;
146435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunneimport android.view.textservice.SuggestionsInfo;
156435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunneimport android.view.textservice.TextInfo;
166435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunneimport android.view.textservice.TextServicesManager;
176435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
186435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunneimport com.android.internal.util.ArrayUtils;
196435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
206435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunneimport java.util.Locale;
216435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
226435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
236435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne/**
246435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne * Helper class for TextView. Bridge between the TextView and the Dictionnary service.
256435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne *
266435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne * @hide
276435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne */
286435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunnepublic class SpellChecker implements SpellCheckerSessionListener {
296435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    private static final String LOG_TAG = "SpellChecker";
306435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    private static final boolean DEBUG_SPELL_CHECK = false;
316435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    private static final int DELAY_BEFORE_SPELL_CHECK = 400; // milliseconds
326435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
336435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    private final TextView mTextView;
346435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
356435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    final SpellCheckerSession spellCheckerSession;
366435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    final int mCookie;
376435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
386435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    // Paired arrays for the (id, spellCheckSpan) pair. mIndex is the next available position
396435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    private int[] mIds;
406435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    private SpellCheckSpan[] mSpellCheckSpans;
416435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    // The actual current number of used slots in the above arrays
426435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    private int mLength;
436435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
446435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    private int mSpanSequenceCounter = 0;
456435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    private Runnable mChecker;
466435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
476435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    public SpellChecker(TextView textView) {
486435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        mTextView = textView;
496435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
506435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        final TextServicesManager textServicesManager = (TextServicesManager) textView.getContext().
516435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
526435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        spellCheckerSession = textServicesManager.newSpellCheckerSession(
536435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                null /* not currently used by the textServicesManager */, Locale.getDefault(),
546435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                this, true /* means use the languages defined in Settings */);
556435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        mCookie = hashCode();
566435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
576435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        // Arbitrary: 4 simultaneous spell check spans. Will automatically double size on demand
586435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        final int size = ArrayUtils.idealObjectArraySize(4);
596435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        mIds = new int[size];
606435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        mSpellCheckSpans = new SpellCheckSpan[size];
616435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        mLength = 0;
626435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    }
636435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
646435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    public void addSpellCheckSpan(SpellCheckSpan spellCheckSpan) {
656435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        int length = mIds.length;
666435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        if (mLength >= length) {
676435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            final int newSize = length * 2;
686435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            int[] newIds = new int[newSize];
696435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            SpellCheckSpan[] newSpellCheckSpans = new SpellCheckSpan[newSize];
706435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            System.arraycopy(mIds, 0, newIds, 0, length);
716435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            System.arraycopy(mSpellCheckSpans, 0, newSpellCheckSpans, 0, length);
726435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            mIds = newIds;
736435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            mSpellCheckSpans = newSpellCheckSpans;
746435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        }
756435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
766435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        mIds[mLength] = mSpanSequenceCounter++;
776435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        mSpellCheckSpans[mLength] = spellCheckSpan;
786435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        mLength++;
796435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
806435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        if (DEBUG_SPELL_CHECK) {
816435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            final Editable mText = (Editable) mTextView.getText();
826435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            int start = mText.getSpanStart(spellCheckSpan);
836435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            int end = mText.getSpanEnd(spellCheckSpan);
846435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            if (start >= 0 && end >= 0) {
856435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                Log.d(LOG_TAG, "Schedule check " + mText.subSequence(start, end));
866435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            } else {
876435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                Log.d(LOG_TAG, "Schedule check   EMPTY!");
886435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            }
896435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        }
906435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
916435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        scheduleSpellCheck();
926435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    }
936435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
946435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    public void removeSpellCheckSpan(SpellCheckSpan spellCheckSpan) {
956435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        for (int i = 0; i < mLength; i++) {
966435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            if (mSpellCheckSpans[i] == spellCheckSpan) {
976435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                removeAtIndex(i);
986435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                return;
996435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            }
1006435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        }
1016435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    }
1026435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
1036435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    private void removeAtIndex(int i) {
1046435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        System.arraycopy(mIds, i + 1, mIds, i, mLength - i - 1);
1056435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        System.arraycopy(mSpellCheckSpans, i + 1, mSpellCheckSpans, i, mLength - i - 1);
1066435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        mLength--;
1076435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    }
1086435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
1096435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    public void onSelectionChanged() {
1106435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        scheduleSpellCheck();
1116435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    }
1126435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
1136435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    private void scheduleSpellCheck() {
1146435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        if (mLength == 0) return;
1156435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        if (mChecker != null) {
1166435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            mTextView.removeCallbacks(mChecker);
1176435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        }
1186435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        if (mChecker == null) {
1196435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            mChecker = new Runnable() {
1206435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                public void run() {
1216435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                  spellCheck();
1226435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                }
1236435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            };
1246435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        }
1256435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        mTextView.postDelayed(mChecker, DELAY_BEFORE_SPELL_CHECK);
1266435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    }
1276435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
1286435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    private void spellCheck() {
1296435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        final Editable editable = (Editable) mTextView.getText();
1306435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        final int selectionStart = Selection.getSelectionStart(editable);
1316435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        final int selectionEnd = Selection.getSelectionEnd(editable);
1326435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
1336435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        TextInfo[] textInfos = new TextInfo[mLength];
1346435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        int textInfosCount = 0;
1356435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
1366435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        for (int i = 0; i < mLength; i++) {
1376435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            SpellCheckSpan spellCheckSpan = mSpellCheckSpans[i];
1386435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
1396435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            if (spellCheckSpan.isSpellCheckInProgress()) continue;
1406435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
1416435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            final int start = editable.getSpanStart(spellCheckSpan);
1426435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            final int end = editable.getSpanEnd(spellCheckSpan);
1436435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
1446435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            // Do not check this word if the user is currently editing it
145d6e3494421dff2a091f1011e5266b280b2109843Gilles Debunne            if (start >= 0 && end > start && (selectionEnd < start || selectionStart > end)) {
1466435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                final String word = editable.subSequence(start, end).toString();
1476435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                spellCheckSpan.setSpellCheckInProgress();
1486435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                textInfos[textInfosCount++] = new TextInfo(word, mCookie, mIds[i]);
1496435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            }
1506435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        }
1516435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
1526435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        if (textInfosCount > 0) {
1536435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            if (textInfosCount < mLength) {
1546435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                TextInfo[] textInfosCopy = new TextInfo[textInfosCount];
1556435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                System.arraycopy(textInfos, 0, textInfosCopy, 0, textInfosCount);
1566435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                textInfos = textInfosCopy;
1576435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            }
1586435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            spellCheckerSession.getSuggestions(textInfos, SuggestionSpan.SUGGESTIONS_MAX_SIZE,
1596435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                    false /* TODO Set sequentialWords to true for initial spell check */);
1606435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        }
1616435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    }
1626435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
1636435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    @Override
1646435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    public void onGetSuggestions(SuggestionsInfo[] results) {
1656435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        final Editable editable = (Editable) mTextView.getText();
1666435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        for (int i = 0; i < results.length; i++) {
1676435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            SuggestionsInfo suggestionsInfo = results[i];
1686435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            if (suggestionsInfo.getCookie() != mCookie) continue;
1696435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
1706435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            final int sequenceNumber = suggestionsInfo.getSequence();
1716435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            // Starting from the end, to limit the number of array copy while removing
1726435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            for (int j = mLength - 1; j >= 0; j--) {
1736435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                if (sequenceNumber == mIds[j]) {
1746435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                    SpellCheckSpan spellCheckSpan = mSpellCheckSpans[j];
1756435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                    final int attributes = suggestionsInfo.getSuggestionsAttributes();
1766435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                    boolean isInDictionary =
1776435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                            ((attributes & SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY) > 0);
1786435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                    boolean looksLikeTypo =
1796435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                            ((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) > 0);
1806435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
1816435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                    if (DEBUG_SPELL_CHECK) {
1826435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                        final int start = editable.getSpanStart(spellCheckSpan);
1836435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                        final int end = editable.getSpanEnd(spellCheckSpan);
1846435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                        Log.d(LOG_TAG, "Result sequence=" + suggestionsInfo.getSequence() + " " +
1856435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                                editable.subSequence(start, end) +
1866435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                                "\t" + (isInDictionary?"IN_DICT" : "NOT_DICT") +
1876435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                                "\t" + (looksLikeTypo?"TYPO" : "NOT_TYPO"));
1886435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                    }
1896435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
1906435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                    if (!isInDictionary && looksLikeTypo) {
1916435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                        String[] suggestions = getSuggestions(suggestionsInfo);
1926435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                        if (suggestions.length > 0) {
1936435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                            SuggestionSpan suggestionSpan = new SuggestionSpan(
1946435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                                    mTextView.getContext(), suggestions,
1956435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                                    SuggestionSpan.FLAG_EASY_CORRECT |
1966435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                                    SuggestionSpan.FLAG_MISSPELLED);
1976435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                            final int start = editable.getSpanStart(spellCheckSpan);
1986435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                            final int end = editable.getSpanEnd(spellCheckSpan);
1996435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                            editable.setSpan(suggestionSpan, start, end,
2006435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
2016435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                            // TODO limit to the word rectangle region
2026435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                            mTextView.invalidate();
2036435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
2046435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                            if (DEBUG_SPELL_CHECK) {
2056435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                                String suggestionsString = "";
2066435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                                for (String s : suggestions) { suggestionsString += s + "|"; }
2076435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                                Log.d(LOG_TAG, "  Suggestions for " + sequenceNumber + " " +
2086435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                                    editable.subSequence(start, end)+ "  " + suggestionsString);
2096435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                            }
2106435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                        }
2116435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                    }
2126435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                    editable.removeSpan(spellCheckSpan);
2136435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne                }
2146435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            }
2156435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        }
2166435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    }
2176435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne
2186435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    private static String[] getSuggestions(SuggestionsInfo suggestionsInfo) {
2196435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        final int len = Math.max(0, suggestionsInfo.getSuggestionsCount());
2206435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        String[] suggestions = new String[len];
2216435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        for (int j = 0; j < len; ++j) {
2226435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne            suggestions[j] = suggestionsInfo.getSuggestionAt(j);
2236435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        }
2246435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne        return suggestions;
2256435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne    }
2266435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne}
227