Merge "Get rid of "isSentenceLevelSpellCheckSupported""

This commit is contained in:
satok
2012-04-16 22:07:45 -07:00
committed by Android (Google) Code Review
7 changed files with 184 additions and 44 deletions

View File

@@ -534,7 +534,7 @@ package android {
field public static final int imeSubtypeLocale = 16843500; // 0x10102ec
field public static final int imeSubtypeMode = 16843501; // 0x10102ed
field public static final int immersive = 16843456; // 0x10102c0
field public static final int importantForAccessibility = 16843699; // 0x10103b3
field public static final int importantForAccessibility = 16843698; // 0x10103b2
field public static final int inAnimation = 16843127; // 0x1010177
field public static final int includeFontPadding = 16843103; // 0x101015f
field public static final int includeInGlobalSearch = 16843374; // 0x101026e
@@ -936,7 +936,6 @@ package android {
field public static final int summaryOff = 16843248; // 0x10101f0
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportsRtl = 16843688; // 0x10103a8
field public static final int supportsSentenceSpellCheck = 16843698; // 0x10103b2
field public static final int supportsUploading = 16843419; // 0x101029b
field public static final int switchMinWidth = 16843632; // 0x1010370
field public static final int switchPadding = 16843633; // 0x1010371
@@ -25520,9 +25519,8 @@ package android.view.textservice {
method public void close();
method public void getSentenceSuggestions(android.view.textservice.TextInfo[], int);
method public android.view.textservice.SpellCheckerInfo getSpellChecker();
method public void getSuggestions(android.view.textservice.TextInfo, int);
method public void getSuggestions(android.view.textservice.TextInfo[], int, boolean);
method public boolean isSentenceSpellCheckSupported();
method public deprecated void getSuggestions(android.view.textservice.TextInfo, int);
method public deprecated void getSuggestions(android.view.textservice.TextInfo[], int, boolean);
method public boolean isSessionDisconnected();
field public static final java.lang.String SERVICE_META_DATA = "android.view.textservice.scs";
}

View File

@@ -26,12 +26,18 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.text.TextUtils;
import android.text.method.WordIterator;
import android.util.Log;
import android.view.textservice.SentenceSuggestionsInfo;
import android.view.textservice.SuggestionsInfo;
import android.view.textservice.TextInfo;
import android.widget.SpellChecker;
import java.lang.ref.WeakReference;
import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.Locale;
/**
* SpellCheckerService provides an abstract base class for a spell checker.
@@ -92,6 +98,7 @@ public abstract class SpellCheckerService extends Service {
*/
public static abstract class Session {
private InternalISpellCheckerSession mInternalSession;
private volatile SentenceLevelAdapter mSentenceLevelAdapter;
/**
* @hide
@@ -142,8 +149,8 @@ public abstract class SpellCheckerService extends Service {
/**
* Get sentence suggestions for specified texts in an array of TextInfo.
* The default implementation returns an array of SentenceSuggestionsInfo by simply
* calling onGetSuggestions.
* The default implementation splits the input text to words and returns
* {@link SentenceSuggestionsInfo} which contains suggestions for each word.
* This function will run on the incoming IPC thread.
* So, this is not called on the main thread,
* but will be called in series on another thread.
@@ -156,14 +163,41 @@ public abstract class SpellCheckerService extends Service {
*/
public SentenceSuggestionsInfo[] onGetSentenceSuggestionsMultiple(TextInfo[] textInfos,
int suggestionsLimit) {
final int length = textInfos.length;
final SentenceSuggestionsInfo[] retval = new SentenceSuggestionsInfo[length];
for (int i = 0; i < length; ++i) {
final SuggestionsInfo si = onGetSuggestions(textInfos[i], suggestionsLimit);
si.setCookieAndSequence(textInfos[i].getCookie(), textInfos[i].getSequence());
final int N = textInfos[i].getText().length();
retval[i] = new SentenceSuggestionsInfo(
new SuggestionsInfo[] {si}, new int[]{0}, new int[]{N});
if (textInfos == null || textInfos.length == 0) {
return SentenceLevelAdapter.EMPTY_SENTENCE_SUGGESTIONS_INFOS;
}
if (DBG) {
Log.d(TAG, "onGetSentenceSuggestionsMultiple: + " + textInfos.length + ", "
+ suggestionsLimit);
}
if (mSentenceLevelAdapter == null) {
synchronized(this) {
if (mSentenceLevelAdapter == null) {
final String localeStr = getLocale();
if (!TextUtils.isEmpty(localeStr)) {
mSentenceLevelAdapter = new SentenceLevelAdapter(new Locale(localeStr));
}
}
}
}
if (mSentenceLevelAdapter == null) {
return SentenceLevelAdapter.EMPTY_SENTENCE_SUGGESTIONS_INFOS;
}
final int infosSize = textInfos.length;
final SentenceSuggestionsInfo[] retval = new SentenceSuggestionsInfo[infosSize];
for (int i = 0; i < infosSize; ++i) {
final SentenceLevelAdapter.SentenceTextInfoParams textInfoParams =
mSentenceLevelAdapter.getSplitWords(textInfos[i]);
final ArrayList<SentenceLevelAdapter.SentenceWordItem> mItems =
textInfoParams.mItems;
final int itemsSize = mItems.size();
final TextInfo[] splitTextInfos = new TextInfo[itemsSize];
for (int j = 0; j < itemsSize; ++j) {
splitTextInfos[j] = mItems.get(j).mTextInfo;
}
retval[i] = SentenceLevelAdapter.reconstructSuggestions(
textInfoParams, onGetSuggestionsMultiple(
splitTextInfos, suggestionsLimit, true));
}
return retval;
}
@@ -290,4 +324,135 @@ public abstract class SpellCheckerService extends Service {
return internalSession;
}
}
/**
* Adapter class to accommodate word level spell checking APIs to sentence level spell checking
* APIs used in
* {@link SpellCheckerService.Session#onGetSuggestionsMultiple(TextInfo[], int, boolean)}
*/
private static class SentenceLevelAdapter {
public static final SentenceSuggestionsInfo[] EMPTY_SENTENCE_SUGGESTIONS_INFOS =
new SentenceSuggestionsInfo[] {};
private static final SuggestionsInfo EMPTY_SUGGESTIONS_INFO = new SuggestionsInfo(0, null);
/**
* Container for split TextInfo parameters
*/
public static class SentenceWordItem {
public final TextInfo mTextInfo;
public final int mStart;
public final int mLength;
public SentenceWordItem(TextInfo ti, int start, int end) {
mTextInfo = ti;
mStart = start;
mLength = end - start;
}
}
/**
* Container for originally queried TextInfo and parameters
*/
public static class SentenceTextInfoParams {
final TextInfo mOriginalTextInfo;
final ArrayList<SentenceWordItem> mItems;
final int mSize;
public SentenceTextInfoParams(TextInfo ti, ArrayList<SentenceWordItem> items) {
mOriginalTextInfo = ti;
mItems = items;
mSize = items.size();
}
}
private final WordIterator mWordIterator;
public SentenceLevelAdapter(Locale locale) {
mWordIterator = new WordIterator(locale);
}
private SentenceTextInfoParams getSplitWords(TextInfo originalTextInfo) {
final WordIterator wordIterator = mWordIterator;
final CharSequence originalText = originalTextInfo.getText();
final int cookie = originalTextInfo.getCookie();
final int start = 0;
final int end = originalText.length();
final ArrayList<SentenceWordItem> wordItems = new ArrayList<SentenceWordItem>();
wordIterator.setCharSequence(originalText, 0, originalText.length());
int wordEnd = wordIterator.following(start);
int wordStart = wordIterator.getBeginning(wordEnd);
if (DBG) {
Log.d(TAG, "iterator: break: ---- 1st word start = " + wordStart + ", end = "
+ wordEnd + "\n" + originalText);
}
while (wordStart <= end && wordEnd != BreakIterator.DONE
&& wordStart != BreakIterator.DONE) {
if (wordEnd >= start && wordEnd > wordStart) {
final String query = originalText.subSequence(wordStart, wordEnd).toString();
final TextInfo ti = new TextInfo(query, cookie, query.hashCode());
wordItems.add(new SentenceWordItem(ti, wordStart, wordEnd));
if (DBG) {
Log.d(TAG, "Adapter: word (" + (wordItems.size() - 1) + ") " + query);
}
}
wordEnd = wordIterator.following(wordEnd);
if (wordEnd == BreakIterator.DONE) {
break;
}
wordStart = wordIterator.getBeginning(wordEnd);
}
if (originalText.length() >= SpellChecker.WORD_ITERATOR_INTERVAL
&& wordItems.size() >= 2) {
if (DBG) {
Log.w(TAG, "Remove possibly divided word: "
+ wordItems.get(0).mTextInfo.getText());
}
wordItems.remove(0);
}
return new SentenceTextInfoParams(originalTextInfo, wordItems);
}
public static SentenceSuggestionsInfo reconstructSuggestions(
SentenceTextInfoParams originalTextInfoParams, SuggestionsInfo[] results) {
if (results == null || results.length == 0) {
return null;
}
if (DBG) {
Log.w(TAG, "Adapter: onGetSuggestions: got " + results.length);
}
if (originalTextInfoParams == null) {
if (DBG) {
Log.w(TAG, "Adapter: originalTextInfoParams is null.");
}
return null;
}
final int originalCookie = originalTextInfoParams.mOriginalTextInfo.getCookie();
final int originalSequence =
originalTextInfoParams.mOriginalTextInfo.getSequence();
final int querySize = originalTextInfoParams.mSize;
final int[] offsets = new int[querySize];
final int[] lengths = new int[querySize];
final SuggestionsInfo[] reconstructedSuggestions = new SuggestionsInfo[querySize];
for (int i = 0; i < querySize; ++i) {
final SentenceWordItem item = originalTextInfoParams.mItems.get(i);
SuggestionsInfo result = null;
for (int j = 0; j < results.length; ++j) {
final SuggestionsInfo cur = results[j];
if (cur != null && cur.getSequence() == item.mTextInfo.getSequence()) {
result = cur;
result.setCookieAndSequence(originalCookie, originalSequence);
break;
}
}
offsets[i] = item.mStart;
lengths[i] = item.mLength;
reconstructedSuggestions[i] = result != null ? result : EMPTY_SUGGESTIONS_INFO;
if (DBG) {
final int size = reconstructedSuggestions[i].getSuggestionsCount();
Log.w(TAG, "reconstructedSuggestions(" + i + ")" + size + ", first = "
+ (size > 0 ? reconstructedSuggestions[i].getSuggestionAt(0)
: "<none>") + ", offset = " + offsets[i] + ", length = "
+ lengths[i]);
}
}
return new SentenceSuggestionsInfo(reconstructedSuggestions, offsets, lengths);
}
}
}

View File

@@ -45,7 +45,6 @@ public final class SpellCheckerInfo implements Parcelable {
private final ResolveInfo mService;
private final String mId;
private final int mLabel;
private final boolean mSupportsSentenceSpellCheck;
/**
* The spell checker setting activity's name, used by the system settings to
@@ -98,9 +97,6 @@ public final class SpellCheckerInfo implements Parcelable {
label = sa.getResourceId(com.android.internal.R.styleable.SpellChecker_label, 0);
settingsActivityComponent = sa.getString(
com.android.internal.R.styleable.SpellChecker_settingsActivity);
mSupportsSentenceSpellCheck = sa.getBoolean(
com.android.internal.R.styleable.SpellChecker_supportsSentenceSpellCheck,
false);
sa.recycle();
final int depth = parser.getDepth();
@@ -142,7 +138,6 @@ public final class SpellCheckerInfo implements Parcelable {
*/
public SpellCheckerInfo(Parcel source) {
mLabel = source.readInt();
mSupportsSentenceSpellCheck = source.readInt() != 0;
mId = source.readString();
mSettingsActivityName = source.readString();
mService = ResolveInfo.CREATOR.createFromParcel(source);
@@ -157,13 +152,6 @@ public final class SpellCheckerInfo implements Parcelable {
return mId;
}
/**
* @hide
*/
public boolean isSentenceSpellCheckSupported() {
return mSupportsSentenceSpellCheck;
}
/**
* Return the component of the service that implements.
*/
@@ -188,7 +176,6 @@ public final class SpellCheckerInfo implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mLabel);
dest.writeInt(mSupportsSentenceSpellCheck ? 1 : 0);
dest.writeString(mId);
dest.writeString(mSettingsActivityName);
mService.writeToParcel(dest, flags);

View File

@@ -91,8 +91,6 @@ public class SpellCheckerSession {
* This meta-data must reference an XML resource.
**/
public static final String SERVICE_META_DATA = "android.view.textservice.scs";
private static final String SUPPORT_SENTENCE_SPELL_CHECK = "SupportSentenceSpellCheck";
private static final int MSG_ON_GET_SUGGESTION_MULTIPLE = 1;
private static final int MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE = 2;
@@ -191,7 +189,9 @@ public class SpellCheckerSession {
* Get candidate strings for a substring of the specified text.
* @param textInfo text metadata for a spell checker
* @param suggestionsLimit the maximum number of suggestions that will be returned
* @deprecated use {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)} instead
*/
@Deprecated
public void getSuggestions(TextInfo textInfo, int suggestionsLimit) {
getSuggestions(new TextInfo[] {textInfo}, suggestionsLimit, false);
}
@@ -201,13 +201,14 @@ public class SpellCheckerSession {
* @param textInfos an array of text metadata for a spell checker
* @param suggestionsLimit the maximum number of suggestions that will be returned
* @param sequentialWords true if textInfos can be treated as sequential words.
* @deprecated use {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)} instead
*/
@Deprecated
public void getSuggestions(
TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
if (DBG) {
Log.w(TAG, "getSuggestions from " + mSpellCheckerInfo.getId());
}
// TODO: Handle multiple words suggestions by using WordBreakIterator
mSpellCheckerSessionListenerImpl.getSuggestionsMultiple(
textInfos, suggestionsLimit, sequentialWords);
}
@@ -281,7 +282,7 @@ public class SpellCheckerSession {
break;
case TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE:
if (DBG) {
Log.w(TAG, "Get suggestions from the spell checker.");
Log.w(TAG, "Get sentence suggestions from the spell checker.");
}
try {
session.onGetSentenceSuggestionsMultiple(
@@ -492,11 +493,4 @@ public class SpellCheckerSession {
public ISpellCheckerSessionListener getSpellCheckerSessionListener() {
return mSpellCheckerSessionListenerImpl;
}
/**
* @return true if the spell checker supports sentence level spell checking APIs
*/
public boolean isSentenceSpellCheckSupported() {
return mSubtype.containsExtraValueKey(SUPPORT_SENTENCE_SPELL_CHECK);
}
}

View File

@@ -116,7 +116,7 @@ public class SpellChecker implements SpellCheckerSessionListener {
null /* Bundle not currently used by the textServicesManager */,
mCurrentLocale, this,
false /* means any available languages from current spell checker */);
mIsSentenceSpellCheckSupported = mSpellCheckerSession.isSentenceSpellCheckSupported();
mIsSentenceSpellCheckSupported = true;
}
// Restore SpellCheckSpans in pool

View File

@@ -2367,8 +2367,6 @@
<!-- Component name of an activity that allows the user to modify
the settings for this service. -->
<attr name="settingsActivity"/>
<!-- Set true when the spell checker supports sentence level spell checking. -->
<attr name="supportsSentenceSpellCheck" format="boolean" />
</declare-styleable>
<!-- This is the subtype of the spell checker. Subtype can describe locales (e.g. en_US, fr_FR...) -->

View File

@@ -3588,8 +3588,6 @@
<public type="attr" name="parentActivityName" />
<public type="attr" name="supportsSentenceSpellCheck" />
<public type="attr" name="importantForAccessibility"/>
</resources>