/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.android.inputmethod.latin.spellcheck; import android.text.TextUtils; import android.util.Log; import android.view.textservice.SentenceSuggestionsInfo; import android.view.textservice.SuggestionsInfo; import android.view.textservice.TextInfo; import com.android.inputmethod.latin.CollectionUtils; import java.util.ArrayList; public final class AndroidSpellCheckerSession extends AndroidWordLevelSpellCheckerSession { private static final String TAG = AndroidSpellCheckerSession.class.getSimpleName(); private static final boolean DBG = false; private final static String[] EMPTY_STRING_ARRAY = new String[0]; public AndroidSpellCheckerSession(AndroidSpellCheckerService service) { super(service); } private SentenceSuggestionsInfo fixWronglyInvalidatedWordWithSingleQuote(TextInfo ti, SentenceSuggestionsInfo ssi) { final String typedText = ti.getText(); if (!typedText.contains(AndroidSpellCheckerService.SINGLE_QUOTE)) { return null; } final int N = ssi.getSuggestionsCount(); final ArrayList additionalOffsets = CollectionUtils.newArrayList(); final ArrayList additionalLengths = CollectionUtils.newArrayList(); final ArrayList additionalSuggestionsInfos = CollectionUtils.newArrayList(); String currentWord = null; for (int i = 0; i < N; ++i) { final SuggestionsInfo si = ssi.getSuggestionsInfoAt(i); final int flags = si.getSuggestionsAttributes(); if ((flags & SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY) == 0) { continue; } final int offset = ssi.getOffsetAt(i); final int length = ssi.getLengthAt(i); final String subText = typedText.substring(offset, offset + length); final String prevWord = currentWord; currentWord = subText; if (!subText.contains(AndroidSpellCheckerService.SINGLE_QUOTE)) { continue; } final String[] splitTexts = subText.split(AndroidSpellCheckerService.SINGLE_QUOTE, -1); if (splitTexts == null || splitTexts.length <= 1) { continue; } final int splitNum = splitTexts.length; for (int j = 0; j < splitNum; ++j) { final String splitText = splitTexts[j]; if (TextUtils.isEmpty(splitText)) { continue; } if (mSuggestionsCache.getSuggestionsFromCache(splitText, prevWord) == null) { continue; } final int newLength = splitText.length(); // Neither RESULT_ATTR_IN_THE_DICTIONARY nor RESULT_ATTR_LOOKS_LIKE_TYPO final int newFlags = 0; final SuggestionsInfo newSi = new SuggestionsInfo(newFlags, EMPTY_STRING_ARRAY); newSi.setCookieAndSequence(si.getCookie(), si.getSequence()); if (DBG) { Log.d(TAG, "Override and remove old span over: " + splitText + ", " + offset + "," + newLength); } additionalOffsets.add(offset); additionalLengths.add(newLength); additionalSuggestionsInfos.add(newSi); } } final int additionalSize = additionalOffsets.size(); if (additionalSize <= 0) { return null; } final int suggestionsSize = N + additionalSize; final int[] newOffsets = new int[suggestionsSize]; final int[] newLengths = new int[suggestionsSize]; final SuggestionsInfo[] newSuggestionsInfos = new SuggestionsInfo[suggestionsSize]; int i; for (i = 0; i < N; ++i) { newOffsets[i] = ssi.getOffsetAt(i); newLengths[i] = ssi.getLengthAt(i); newSuggestionsInfos[i] = ssi.getSuggestionsInfoAt(i); } for (; i < suggestionsSize; ++i) { newOffsets[i] = additionalOffsets.get(i - N); newLengths[i] = additionalLengths.get(i - N); newSuggestionsInfos[i] = additionalSuggestionsInfos.get(i - N); } return new SentenceSuggestionsInfo(newSuggestionsInfos, newOffsets, newLengths); } @Override public SentenceSuggestionsInfo[] onGetSentenceSuggestionsMultiple(TextInfo[] textInfos, int suggestionsLimit) { final SentenceSuggestionsInfo[] retval = super.onGetSentenceSuggestionsMultiple(textInfos, suggestionsLimit); if (retval == null || retval.length != textInfos.length) { return retval; } for (int i = 0; i < retval.length; ++i) { final SentenceSuggestionsInfo tempSsi = fixWronglyInvalidatedWordWithSingleQuote(textInfos[i], retval[i]); if (tempSsi != null) { retval[i] = tempSsi; } } return retval; } @Override public SuggestionsInfo[] onGetSuggestionsMultiple(TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) { final int length = textInfos.length; final SuggestionsInfo[] retval = new SuggestionsInfo[length]; for (int i = 0; i < length; ++i) { final String prevWord; if (sequentialWords && i > 0) { final String prevWordCandidate = textInfos[i - 1].getText(); // Note that an empty string would be used to indicate the initial word // in the future. prevWord = TextUtils.isEmpty(prevWordCandidate) ? null : prevWordCandidate; } else { prevWord = null; } retval[i] = onGetSuggestions(textInfos[i], prevWord, suggestionsLimit); retval[i].setCookieAndSequence(textInfos[i].getCookie(), textInfos[i].getSequence()); } return retval; } }