/*
* Copyright (c) 2013 Menny Even-Danan
*
* 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.anysoftkeyboard.spellcheck;
import android.annotation.TargetApi;
import android.os.Build;
import android.service.textservice.SpellCheckerService;
import android.text.TextUtils;
import android.view.textservice.SuggestionsInfo;
import android.view.textservice.TextInfo;
import com.anysoftkeyboard.utils.Log;
import com.menny.android.anysoftkeyboard.FeaturesSet;
/**
* Service for spell checking, using ASK dictionaries and mechanisms.
*/
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public class AnySpellCheckerService extends SpellCheckerService {
static final String TAG = "ASK_SPELL";
static final boolean DBG = FeaturesSet.DEBUG_LOG;
static final String[] EMPTY_STRING_ARRAY = new String[0];
@Override
public void onCreate() {
super.onCreate();
}
@Override
public Session createSession() {
return new AnySpellCheckerSession();
}
private static SuggestionsInfo getNotInDictEmptySuggestions() {
return new SuggestionsInfo(0, EMPTY_STRING_ARRAY);
}
private static SuggestionsInfo getInDictEmptySuggestions() {
return new SuggestionsInfo(
SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY,
EMPTY_STRING_ARRAY);
}
private static class AnySpellCheckerSession extends Session {
AnySpellCheckerSession() {
}
/**
* Finds out whether a particular string should be filtered out of spell
* checking.
* <p/>
* This will loosely match URLs, numbers, symbols.
*
* @param text the string to evaluate.
* @return true if we should filter this text out, false otherwise
*/
private static boolean shouldFilterOut(final String text) {
if (TextUtils.isEmpty(text) || text.length() <= 1)
return true;
// TODO: check if an equivalent processing can't be done more
// quickly with a
// compiled regexp.
// Filter by first letter
final int firstCodePoint = text.codePointAt(0);
// Filter out words that don't start with a letter or an apostrophe
if (!Character.isLetter(firstCodePoint) && '\'' != firstCodePoint)
return true;
// Filter contents
final int length = text.length();
int letterCount = 0;
for (int i = 0; i < length; ++i) {
final int codePoint = text.codePointAt(i);
// Any word containing a '@' is probably an e-mail address
// Any word containing a '/' is probably either an ad-hoc
// combination of two
// words or a URI - in either case we don't want to spell check
// that
if ('@' == codePoint || '/' == codePoint)
return true;
if (Character.isLetter(codePoint))
++letterCount;
}
// Guestimate heuristic: perform spell checking if at least 3/4 of
// the characters
// in this word are letters
return (letterCount * 4 < length * 3);
}
// Note : this must be reentrant
/**
* Gets a list of suggestions for a specific string. This returns a list
* of possible corrections for the text passed as an argument. It may
* split or group words, and even perform grammatical analysis.
*/
@Override
public SuggestionsInfo onGetSuggestions(final TextInfo textInfo,
final int suggestionsLimit) {
try {
final String text = textInfo.getText();
final boolean shouldFilterOut = shouldFilterOut(text);
Log.d(TAG, "onGetSuggestions for '" + text
+ "'. Should filter out? " + shouldFilterOut);
if (!shouldFilterOut) {
//TODO: let's see if the word is in my dictionaries
}
return getNotInDictEmptySuggestions();
} catch (RuntimeException e) {
Log.e(TAG, "Exception caught in ASK SpellChecker!");
e.printStackTrace();
if (DBG)
throw e;// in production crash the entire stack. Swallow it.
return getNotInDictEmptySuggestions();
}
}
@Override
public void onCreate() {
}
}
}