Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c7ee1b93 authored by satok's avatar satok
Browse files

Get rid of "isSentenceLevelSpellCheckSupported"

Bug: 6320351
Change-Id: I0e931b7248f8c65268b60af599c07432d58d2f1f
parent 52c5acac
Loading
Loading
Loading
Loading
+3 −5
Original line number Original line Diff line number Diff line
@@ -534,7 +534,7 @@ package android {
    field public static final int imeSubtypeLocale = 16843500; // 0x10102ec
    field public static final int imeSubtypeLocale = 16843500; // 0x10102ec
    field public static final int imeSubtypeMode = 16843501; // 0x10102ed
    field public static final int imeSubtypeMode = 16843501; // 0x10102ed
    field public static final int immersive = 16843456; // 0x10102c0
    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 inAnimation = 16843127; // 0x1010177
    field public static final int includeFontPadding = 16843103; // 0x101015f
    field public static final int includeFontPadding = 16843103; // 0x101015f
    field public static final int includeInGlobalSearch = 16843374; // 0x101026e
    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 summaryOff = 16843248; // 0x10101f0
    field public static final int summaryOn = 16843247; // 0x10101ef
    field public static final int summaryOn = 16843247; // 0x10101ef
    field public static final int supportsRtl = 16843688; // 0x10103a8
    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 supportsUploading = 16843419; // 0x101029b
    field public static final int switchMinWidth = 16843632; // 0x1010370
    field public static final int switchMinWidth = 16843632; // 0x1010370
    field public static final int switchPadding = 16843633; // 0x1010371
    field public static final int switchPadding = 16843633; // 0x1010371
@@ -25425,9 +25424,8 @@ package android.view.textservice {
    method public void close();
    method public void close();
    method public void getSentenceSuggestions(android.view.textservice.TextInfo[], int);
    method public void getSentenceSuggestions(android.view.textservice.TextInfo[], int);
    method public android.view.textservice.SpellCheckerInfo getSpellChecker();
    method public android.view.textservice.SpellCheckerInfo getSpellChecker();
    method public void getSuggestions(android.view.textservice.TextInfo, int);
    method public deprecated void getSuggestions(android.view.textservice.TextInfo, int);
    method public void getSuggestions(android.view.textservice.TextInfo[], int, boolean);
    method public deprecated void getSuggestions(android.view.textservice.TextInfo[], int, boolean);
    method public boolean isSentenceSpellCheckSupported();
    method public boolean isSessionDisconnected();
    method public boolean isSessionDisconnected();
    field public static final java.lang.String SERVICE_META_DATA = "android.view.textservice.scs";
    field public static final java.lang.String SERVICE_META_DATA = "android.view.textservice.scs";
  }
  }
+175 −10
Original line number Original line Diff line number Diff line
@@ -26,12 +26,18 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.IBinder;
import android.os.Process;
import android.os.Process;
import android.os.RemoteException;
import android.os.RemoteException;
import android.text.TextUtils;
import android.text.method.WordIterator;
import android.util.Log;
import android.util.Log;
import android.view.textservice.SentenceSuggestionsInfo;
import android.view.textservice.SentenceSuggestionsInfo;
import android.view.textservice.SuggestionsInfo;
import android.view.textservice.SuggestionsInfo;
import android.view.textservice.TextInfo;
import android.view.textservice.TextInfo;
import android.widget.SpellChecker;


import java.lang.ref.WeakReference;
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.
 * 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 {
    public static abstract class Session {
        private InternalISpellCheckerSession mInternalSession;
        private InternalISpellCheckerSession mInternalSession;
        private volatile SentenceLevelAdapter mSentenceLevelAdapter;


        /**
        /**
         * @hide
         * @hide
@@ -142,8 +149,8 @@ public abstract class SpellCheckerService extends Service {


        /**
        /**
         * Get sentence suggestions for specified texts in an array of TextInfo.
         * Get sentence suggestions for specified texts in an array of TextInfo.
         * The default implementation returns an array of SentenceSuggestionsInfo by simply
         * The default implementation splits the input text to words and returns
         * calling onGetSuggestions.
         * {@link SentenceSuggestionsInfo} which contains suggestions for each word.
         * This function will run on the incoming IPC thread.
         * This function will run on the incoming IPC thread.
         * So, this is not called on the main thread,
         * So, this is not called on the main thread,
         * but will be called in series on another 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,
        public SentenceSuggestionsInfo[] onGetSentenceSuggestionsMultiple(TextInfo[] textInfos,
                int suggestionsLimit) {
                int suggestionsLimit) {
            final int length = textInfos.length;
            if (textInfos == null || textInfos.length == 0) {
            final SentenceSuggestionsInfo[] retval = new SentenceSuggestionsInfo[length];
                return SentenceLevelAdapter.EMPTY_SENTENCE_SUGGESTIONS_INFOS;
            for (int i = 0; i < length; ++i) {
            }
                final SuggestionsInfo si = onGetSuggestions(textInfos[i], suggestionsLimit);
            if (DBG) {
                si.setCookieAndSequence(textInfos[i].getCookie(), textInfos[i].getSequence());
                Log.d(TAG, "onGetSentenceSuggestionsMultiple: + " + textInfos.length + ", "
                final int N = textInfos[i].getText().length();
                        + suggestionsLimit);
                retval[i] = new SentenceSuggestionsInfo(
            }
                        new SuggestionsInfo[] {si}, new int[]{0}, new int[]{N});
            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;
            return retval;
        }
        }
@@ -290,4 +324,135 @@ public abstract class SpellCheckerService extends Service {
            return internalSession;
            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);
        }
    }
}
}
+0 −13
Original line number Original line Diff line number Diff line
@@ -45,7 +45,6 @@ public final class SpellCheckerInfo implements Parcelable {
    private final ResolveInfo mService;
    private final ResolveInfo mService;
    private final String mId;
    private final String mId;
    private final int mLabel;
    private final int mLabel;
    private final boolean mSupportsSentenceSpellCheck;


    /**
    /**
     * The spell checker setting activity's name, used by the system settings to
     * 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);
            label = sa.getResourceId(com.android.internal.R.styleable.SpellChecker_label, 0);
            settingsActivityComponent = sa.getString(
            settingsActivityComponent = sa.getString(
                    com.android.internal.R.styleable.SpellChecker_settingsActivity);
                    com.android.internal.R.styleable.SpellChecker_settingsActivity);
            mSupportsSentenceSpellCheck = sa.getBoolean(
                    com.android.internal.R.styleable.SpellChecker_supportsSentenceSpellCheck,
                    false);
            sa.recycle();
            sa.recycle();


            final int depth = parser.getDepth();
            final int depth = parser.getDepth();
@@ -142,7 +138,6 @@ public final class SpellCheckerInfo implements Parcelable {
     */
     */
    public SpellCheckerInfo(Parcel source) {
    public SpellCheckerInfo(Parcel source) {
        mLabel = source.readInt();
        mLabel = source.readInt();
        mSupportsSentenceSpellCheck = source.readInt() != 0;
        mId = source.readString();
        mId = source.readString();
        mSettingsActivityName = source.readString();
        mSettingsActivityName = source.readString();
        mService = ResolveInfo.CREATOR.createFromParcel(source);
        mService = ResolveInfo.CREATOR.createFromParcel(source);
@@ -157,13 +152,6 @@ public final class SpellCheckerInfo implements Parcelable {
        return mId;
        return mId;
    }
    }


    /**
     * @hide
     */
    public boolean isSentenceSpellCheckSupported() {
        return mSupportsSentenceSpellCheck;
    }

    /**
    /**
     * Return the component of the service that implements.
     * Return the component of the service that implements.
     */
     */
@@ -188,7 +176,6 @@ public final class SpellCheckerInfo implements Parcelable {
    @Override
    @Override
    public void writeToParcel(Parcel dest, int flags) {
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(mLabel);
        dest.writeInt(mLabel);
        dest.writeInt(mSupportsSentenceSpellCheck ? 1 : 0);
        dest.writeString(mId);
        dest.writeString(mId);
        dest.writeString(mSettingsActivityName);
        dest.writeString(mSettingsActivityName);
        mService.writeToParcel(dest, flags);
        mService.writeToParcel(dest, flags);
+5 −11
Original line number Original line Diff line number Diff line
@@ -91,8 +91,6 @@ public class SpellCheckerSession {
     * This meta-data must reference an XML resource.
     * This meta-data must reference an XML resource.
     **/
     **/
    public static final String SERVICE_META_DATA = "android.view.textservice.scs";
    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 = 1;
    private static final int MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE = 2;
    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.
     * Get candidate strings for a substring of the specified text.
     * @param textInfo text metadata for a spell checker
     * @param textInfo text metadata for a spell checker
     * @param suggestionsLimit the maximum number of suggestions that will be returned
     * @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) {
    public void getSuggestions(TextInfo textInfo, int suggestionsLimit) {
        getSuggestions(new TextInfo[] {textInfo}, suggestionsLimit, false);
        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 textInfos an array of text metadata for a spell checker
     * @param suggestionsLimit the maximum number of suggestions that will be returned
     * @param suggestionsLimit the maximum number of suggestions that will be returned
     * @param sequentialWords true if textInfos can be treated as sequential words.
     * @param sequentialWords true if textInfos can be treated as sequential words.
     * @deprecated use {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)} instead
     */
     */
    @Deprecated
    public void getSuggestions(
    public void getSuggestions(
            TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
            TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
        if (DBG) {
        if (DBG) {
            Log.w(TAG, "getSuggestions from " + mSpellCheckerInfo.getId());
            Log.w(TAG, "getSuggestions from " + mSpellCheckerInfo.getId());
        }
        }
        // TODO: Handle multiple words suggestions by using WordBreakIterator
        mSpellCheckerSessionListenerImpl.getSuggestionsMultiple(
        mSpellCheckerSessionListenerImpl.getSuggestionsMultiple(
                textInfos, suggestionsLimit, sequentialWords);
                textInfos, suggestionsLimit, sequentialWords);
    }
    }
@@ -281,7 +282,7 @@ public class SpellCheckerSession {
                        break;
                        break;
                    case TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE:
                    case TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE:
                        if (DBG) {
                        if (DBG) {
                            Log.w(TAG, "Get suggestions from the spell checker.");
                            Log.w(TAG, "Get sentence suggestions from the spell checker.");
                        }
                        }
                        try {
                        try {
                            session.onGetSentenceSuggestionsMultiple(
                            session.onGetSentenceSuggestionsMultiple(
@@ -492,11 +493,4 @@ public class SpellCheckerSession {
    public ISpellCheckerSessionListener getSpellCheckerSessionListener() {
    public ISpellCheckerSessionListener getSpellCheckerSessionListener() {
        return mSpellCheckerSessionListenerImpl;
        return mSpellCheckerSessionListenerImpl;
    }
    }

    /**
     * @return true if the spell checker supports sentence level spell checking APIs
     */
    public boolean isSentenceSpellCheckSupported() {
        return mSubtype.containsExtraValueKey(SUPPORT_SENTENCE_SPELL_CHECK);
    }
}
}
+1 −1
Original line number Original line Diff line number Diff line
@@ -116,7 +116,7 @@ public class SpellChecker implements SpellCheckerSessionListener {
                    null /* Bundle not currently used by the textServicesManager */,
                    null /* Bundle not currently used by the textServicesManager */,
                    mCurrentLocale, this,
                    mCurrentLocale, this,
                    false /* means any available languages from current spell checker */);
                    false /* means any available languages from current spell checker */);
            mIsSentenceSpellCheckSupported = mSpellCheckerSession.isSentenceSpellCheckSupported();
            mIsSentenceSpellCheckSupported = true;
        }
        }


        // Restore SpellCheckSpans in pool
        // Restore SpellCheckSpans in pool
Loading