mirror of
https://gitlab.futo.org/keyboard/latinime.git
synced 2024-09-28 14:54:30 +01:00
Fix case sensitivity for the spell checker.
The new behavior is as follows: - If the word in the dictionary is not fully lower case, then the exact case is required to match. - If the word in the dictionary is fully lower case, then any of the following patterns match: - fully lower case - only the first char capitalized - all caps Any other capitalization is rejected. This is probably what people want. If you type a name in all lower case, it should be marked as a typo, but if you type a word with a capital for emphasis or just because it's the start of the sentence, it should match a lower case word in the dictionary. If you have a spurious capital letter in the middle of a word because of a typo, it should be marked as such. Accents are not affected, and should not be. An accented letter is a different letter and a missing accent should be reported. We should maybe consider again for some common transpositions like the "ue" digraph for German, which is now considered a typo, but will suggest the correct diacritics as the first suggestion. Bug: 5145751 Change-Id: I651e24f13c90fb94700a1674ad380e95336e7dca
This commit is contained in:
parent
cee174b8cc
commit
5d4c5692f1
@ -23,6 +23,7 @@ import android.service.textservice.SpellCheckerService.Session;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.textservice.SuggestionsInfo;
|
import android.view.textservice.SuggestionsInfo;
|
||||||
import android.view.textservice.TextInfo;
|
import android.view.textservice.TextInfo;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.android.inputmethod.compat.ArraysCompatUtils;
|
import com.android.inputmethod.compat.ArraysCompatUtils;
|
||||||
import com.android.inputmethod.keyboard.Key;
|
import com.android.inputmethod.keyboard.Key;
|
||||||
@ -50,7 +51,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
|
|||||||
private static final boolean DBG = false;
|
private static final boolean DBG = false;
|
||||||
private static final int POOL_SIZE = 2;
|
private static final int POOL_SIZE = 2;
|
||||||
|
|
||||||
private final static String[] emptyArray = new String[0];
|
private final static SuggestionsInfo EMPTY_SUGGESTIONS_INFO =
|
||||||
|
new SuggestionsInfo(0, new String[0]);
|
||||||
private Map<String, DictionaryPool> mDictionaryPools =
|
private Map<String, DictionaryPool> mDictionaryPools =
|
||||||
Collections.synchronizedMap(new TreeMap<String, DictionaryPool>());
|
Collections.synchronizedMap(new TreeMap<String, DictionaryPool>());
|
||||||
private Map<String, Dictionary> mUserDictionaries =
|
private Map<String, Dictionary> mUserDictionaries =
|
||||||
@ -153,10 +155,14 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
|
|||||||
private class AndroidSpellCheckerSession extends Session {
|
private class AndroidSpellCheckerSession extends Session {
|
||||||
// Immutable, but need the locale which is not available in the constructor yet
|
// Immutable, but need the locale which is not available in the constructor yet
|
||||||
DictionaryPool mDictionaryPool;
|
DictionaryPool mDictionaryPool;
|
||||||
|
// Likewise
|
||||||
|
Locale mLocale;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
mDictionaryPool = getDictionaryPool(getLocale());
|
final String localeString = getLocale();
|
||||||
|
mDictionaryPool = getDictionaryPool(localeString);
|
||||||
|
mLocale = Utils.constructLocaleFromString(localeString);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note : this must be reentrant
|
// Note : this must be reentrant
|
||||||
@ -170,6 +176,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
|
|||||||
final int suggestionsLimit) {
|
final int suggestionsLimit) {
|
||||||
final String text = textInfo.getText();
|
final String text = textInfo.getText();
|
||||||
|
|
||||||
|
if (TextUtils.isEmpty(text)) return EMPTY_SUGGESTIONS_INFO;
|
||||||
|
|
||||||
final SuggestionsGatherer suggestionsGatherer =
|
final SuggestionsGatherer suggestionsGatherer =
|
||||||
new SuggestionsGatherer(suggestionsLimit);
|
new SuggestionsGatherer(suggestionsLimit);
|
||||||
final WordComposer composer = new WordComposer();
|
final WordComposer composer = new WordComposer();
|
||||||
@ -194,12 +202,32 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
|
|||||||
dictInfo.mDictionary.getWords(composer, suggestionsGatherer,
|
dictInfo.mDictionary.getWords(composer, suggestionsGatherer,
|
||||||
dictInfo.mProximityInfo);
|
dictInfo.mProximityInfo);
|
||||||
isInDict = dictInfo.mDictionary.isValidWord(text);
|
isInDict = dictInfo.mDictionary.isValidWord(text);
|
||||||
|
if (!isInDict && Character.isUpperCase(text.codePointAt(0))) {
|
||||||
|
// If the first char is not uppercase, then the word is either all lower case,
|
||||||
|
// in which case we already tested it, or mixed case, in which case we don't
|
||||||
|
// want to test a lower-case version of it. Hence the test above.
|
||||||
|
// Also note that by isEmpty() test at the top of the method codePointAt(0) is
|
||||||
|
// guaranteed to be there.
|
||||||
|
final int len = text.codePointCount(0, text.length());
|
||||||
|
int capsCount = 1;
|
||||||
|
for (int i = 1; i < len; ++i) {
|
||||||
|
if (1 != capsCount && i != capsCount) break;
|
||||||
|
if (Character.isUpperCase(text.codePointAt(i))) ++capsCount;
|
||||||
|
}
|
||||||
|
// We know the first char is upper case. So we want to test if either everything
|
||||||
|
// else is lower case, or if everything else is upper case. If the string is
|
||||||
|
// exactly one char long, then we will arrive here with capsCount 0, and this is
|
||||||
|
// correct, too.
|
||||||
|
if (1 == capsCount || len == capsCount) {
|
||||||
|
isInDict = dictInfo.mDictionary.isValidWord(text.toLowerCase(mLocale));
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!mDictionaryPool.offer(dictInfo)) {
|
if (!mDictionaryPool.offer(dictInfo)) {
|
||||||
Log.e(TAG, "Can't re-insert a dictionary into its pool");
|
Log.e(TAG, "Can't re-insert a dictionary into its pool");
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
// I don't think this can happen.
|
// I don't think this can happen.
|
||||||
return new SuggestionsInfo(0, new String[0]);
|
return EMPTY_SUGGESTIONS_INFO;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String[] suggestions = suggestionsGatherer.getGatheredSuggestions();
|
final String[] suggestions = suggestionsGatherer.getGatheredSuggestions();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user