2012-07-10 06:33:18 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2012 The Android Open Source Project
|
|
|
|
*
|
2013-01-21 12:52:57 +00:00
|
|
|
* 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
|
2012-07-10 06:33:18 +00:00
|
|
|
*
|
2013-01-21 12:52:57 +00:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2012-07-10 06:33:18 +00:00
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
2013-01-21 12:52:57 +00:00
|
|
|
* 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.
|
2012-07-10 06:33:18 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
package com.android.inputmethod.latin.spellcheck;
|
|
|
|
|
2013-03-15 10:00:51 +00:00
|
|
|
import android.os.Binder;
|
2012-07-10 06:33:18 +00:00
|
|
|
import android.text.TextUtils;
|
|
|
|
import android.util.Log;
|
|
|
|
import android.view.textservice.SentenceSuggestionsInfo;
|
|
|
|
import android.view.textservice.SuggestionsInfo;
|
|
|
|
import android.view.textservice.TextInfo;
|
|
|
|
|
2014-05-19 04:55:40 +00:00
|
|
|
import com.android.inputmethod.latin.PrevWordsInfo;
|
2012-08-21 07:34:55 +00:00
|
|
|
|
2012-07-10 06:33:18 +00:00
|
|
|
import java.util.ArrayList;
|
|
|
|
|
2012-09-27 09:16:16 +00:00
|
|
|
public final class AndroidSpellCheckerSession extends AndroidWordLevelSpellCheckerSession {
|
2012-07-10 06:33:18 +00:00
|
|
|
private static final String TAG = AndroidSpellCheckerSession.class.getSimpleName();
|
|
|
|
private static final boolean DBG = false;
|
|
|
|
private final static String[] EMPTY_STRING_ARRAY = new String[0];
|
|
|
|
|
2012-07-10 08:32:39 +00:00
|
|
|
public AndroidSpellCheckerSession(AndroidSpellCheckerService service) {
|
|
|
|
super(service);
|
2012-07-10 06:33:18 +00:00
|
|
|
}
|
|
|
|
|
2012-07-10 08:32:39 +00:00
|
|
|
private SentenceSuggestionsInfo fixWronglyInvalidatedWordWithSingleQuote(TextInfo ti,
|
|
|
|
SentenceSuggestionsInfo ssi) {
|
2012-07-10 06:33:18 +00:00
|
|
|
final String typedText = ti.getText();
|
|
|
|
if (!typedText.contains(AndroidSpellCheckerService.SINGLE_QUOTE)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
final int N = ssi.getSuggestionsCount();
|
2014-05-23 11:18:17 +00:00
|
|
|
final ArrayList<Integer> additionalOffsets = new ArrayList<>();
|
|
|
|
final ArrayList<Integer> additionalLengths = new ArrayList<>();
|
|
|
|
final ArrayList<SuggestionsInfo> additionalSuggestionsInfos = new ArrayList<>();
|
2012-07-10 06:33:18 +00:00
|
|
|
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);
|
2014-05-19 04:55:40 +00:00
|
|
|
final PrevWordsInfo prevWordsInfo = new PrevWordsInfo(currentWord);
|
2012-07-10 06:33:18 +00:00
|
|
|
currentWord = subText;
|
|
|
|
if (!subText.contains(AndroidSpellCheckerService.SINGLE_QUOTE)) {
|
|
|
|
continue;
|
|
|
|
}
|
2012-07-10 08:32:39 +00:00
|
|
|
final String[] splitTexts =
|
|
|
|
subText.split(AndroidSpellCheckerService.SINGLE_QUOTE, -1);
|
2012-07-10 06:33:18 +00:00
|
|
|
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;
|
|
|
|
}
|
2014-05-19 04:55:40 +00:00
|
|
|
if (mSuggestionsCache.getSuggestionsFromCache(splitText, prevWordsInfo) == null) {
|
2012-07-10 06:33:18 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
final int newLength = splitText.length();
|
|
|
|
// Neither RESULT_ATTR_IN_THE_DICTIONARY nor RESULT_ATTR_LOOKS_LIKE_TYPO
|
|
|
|
final int newFlags = 0;
|
2012-07-10 08:32:39 +00:00
|
|
|
final SuggestionsInfo newSi =
|
|
|
|
new SuggestionsInfo(newFlags, EMPTY_STRING_ARRAY);
|
2012-07-10 06:33:18 +00:00
|
|
|
newSi.setCookieAndSequence(si.getCookie(), si.getSequence());
|
|
|
|
if (DBG) {
|
2012-07-10 08:32:39 +00:00
|
|
|
Log.d(TAG, "Override and remove old span over: " + splitText + ", "
|
|
|
|
+ offset + "," + newLength);
|
2012-07-10 06:33:18 +00:00
|
|
|
}
|
|
|
|
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
|
2012-07-10 08:32:39 +00:00
|
|
|
public SentenceSuggestionsInfo[] onGetSentenceSuggestionsMultiple(TextInfo[] textInfos,
|
|
|
|
int suggestionsLimit) {
|
|
|
|
final SentenceSuggestionsInfo[] retval =
|
|
|
|
super.onGetSentenceSuggestionsMultiple(textInfos, suggestionsLimit);
|
2012-07-10 06:33:18 +00:00
|
|
|
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) {
|
2013-03-15 10:00:51 +00:00
|
|
|
long ident = Binder.clearCallingIdentity();
|
|
|
|
try {
|
|
|
|
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) {
|
2012-07-10 06:33:18 +00:00
|
|
|
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;
|
2013-03-15 10:00:51 +00:00
|
|
|
} else {
|
|
|
|
prevWord = null;
|
|
|
|
}
|
2014-05-19 04:55:40 +00:00
|
|
|
final PrevWordsInfo prevWordsInfo = new PrevWordsInfo(prevWord);
|
|
|
|
retval[i] = onGetSuggestionsInternal(textInfos[i], prevWordsInfo, suggestionsLimit);
|
2013-03-15 10:00:51 +00:00
|
|
|
retval[i].setCookieAndSequence(textInfos[i].getCookie(),
|
|
|
|
textInfos[i].getSequence());
|
2012-07-10 06:33:18 +00:00
|
|
|
}
|
2013-03-15 10:00:51 +00:00
|
|
|
return retval;
|
|
|
|
} finally {
|
|
|
|
Binder.restoreCallingIdentity(ident);
|
2012-07-10 06:33:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|