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

Commit 6b22120e authored by Kohsuke Yatoh's avatar Kohsuke Yatoh
Browse files

InputMethodInfo attr to suppress spell checker.

If InputMethodService declares suppressesSpellChecker="true", the system
SpellCheckerService will be disabled.

With TextView, when IMSs are switched while the user is editing,
SuggestionSpans that were previously added will not be removed even if
the next IMS declares suppressesSpellChecker="true".
This is because we don't know if the SuggestionSpans were from Spell
Checker, App, or IMS.

Bug: 153473490
Test: atest CtsInputMethodTestCases:SpellCheckerTest
Change-Id: Ia22b8758111087818beea8c07b1c173f1a94b8e4
parent 11a7f133
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -1394,6 +1394,7 @@ package android {
    field public static final int supportsRtl = 16843695; // 0x10103af
    field public static final int supportsRtl = 16843695; // 0x10103af
    field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
    field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
    field public static final int supportsUploading = 16843419; // 0x101029b
    field public static final int supportsUploading = 16843419; // 0x101029b
    field public static final int suppressesSpellChecker = 16844354; // 0x1010642
    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
    field public static final int switchPreferenceStyle = 16843629; // 0x101036d
    field public static final int switchPreferenceStyle = 16843629; // 0x101036d
@@ -51469,6 +51470,7 @@ package android.view.inputmethod {
    method public int getSubtypeCount();
    method public int getSubtypeCount();
    method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
    method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
    method public CharSequence loadLabel(android.content.pm.PackageManager);
    method public CharSequence loadLabel(android.content.pm.PackageManager);
    method public boolean suppressesSpellChecker();
    method public void writeToParcel(android.os.Parcel, int);
    method public void writeToParcel(android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.InputMethodInfo> CREATOR;
    field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.InputMethodInfo> CREATOR;
  }
  }
@@ -51490,6 +51492,7 @@ package android.view.inputmethod {
    method public boolean isActive(android.view.View);
    method public boolean isActive(android.view.View);
    method public boolean isActive();
    method public boolean isActive();
    method public boolean isFullscreenMode();
    method public boolean isFullscreenMode();
    method public boolean isInputMethodSuppressingSpellChecker();
    method @Deprecated public boolean isWatchingCursor(android.view.View);
    method @Deprecated public boolean isWatchingCursor(android.view.View);
    method public void restartInput(android.view.View);
    method public void restartInput(android.view.View);
    method public void sendAppPrivateCommand(android.view.View, String, android.os.Bundle);
    method public void sendAppPrivateCommand(android.view.View, String, android.os.Bundle);
+22 −1
Original line number Original line Diff line number Diff line
@@ -60,6 +60,7 @@ import java.util.List;
 * @attr ref android.R.styleable#InputMethod_isDefault
 * @attr ref android.R.styleable#InputMethod_isDefault
 * @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod
 * @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod
 * @attr ref android.R.styleable#InputMethod_supportsInlineSuggestions
 * @attr ref android.R.styleable#InputMethod_supportsInlineSuggestions
 * @attr ref android.R.styleable#InputMethod_suppressesSpellChecker
 */
 */
public final class InputMethodInfo implements Parcelable {
public final class InputMethodInfo implements Parcelable {
    static final String TAG = "InputMethodInfo";
    static final String TAG = "InputMethodInfo";
@@ -117,6 +118,11 @@ public final class InputMethodInfo implements Parcelable {
     */
     */
    private final boolean mInlineSuggestionsEnabled;
    private final boolean mInlineSuggestionsEnabled;


    /**
     * The flag whether this IME suppresses spell checker.
     */
    private final boolean mSuppressesSpellChecker;

    /**
    /**
     * @param service the {@link ResolveInfo} corresponds in which the IME is implemented.
     * @param service the {@link ResolveInfo} corresponds in which the IME is implemented.
     * @return a unique ID to be returned by {@link #getId()}. We have used
     * @return a unique ID to be returned by {@link #getId()}. We have used
@@ -160,6 +166,7 @@ public final class InputMethodInfo implements Parcelable {
        boolean isAuxIme = true;
        boolean isAuxIme = true;
        boolean supportsSwitchingToNextInputMethod = false; // false as default
        boolean supportsSwitchingToNextInputMethod = false; // false as default
        boolean inlineSuggestionsEnabled = false; // false as default
        boolean inlineSuggestionsEnabled = false; // false as default
        boolean suppressesSpellChecker = false; // false as default
        mForceDefault = false;
        mForceDefault = false;


        PackageManager pm = context.getPackageManager();
        PackageManager pm = context.getPackageManager();
@@ -203,6 +210,8 @@ public final class InputMethodInfo implements Parcelable {
                    false);
                    false);
            inlineSuggestionsEnabled = sa.getBoolean(
            inlineSuggestionsEnabled = sa.getBoolean(
                    com.android.internal.R.styleable.InputMethod_supportsInlineSuggestions, false);
                    com.android.internal.R.styleable.InputMethod_supportsInlineSuggestions, false);
            suppressesSpellChecker = sa.getBoolean(
                    com.android.internal.R.styleable.InputMethod_suppressesSpellChecker, false);
            sa.recycle();
            sa.recycle();


            final int depth = parser.getDepth();
            final int depth = parser.getDepth();
@@ -274,6 +283,7 @@ public final class InputMethodInfo implements Parcelable {
        mIsAuxIme = isAuxIme;
        mIsAuxIme = isAuxIme;
        mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
        mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
        mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
        mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
        mSuppressesSpellChecker = suppressesSpellChecker;
        mIsVrOnly = isVrOnly;
        mIsVrOnly = isVrOnly;
    }
    }


@@ -284,6 +294,7 @@ public final class InputMethodInfo implements Parcelable {
        mIsAuxIme = source.readInt() == 1;
        mIsAuxIme = source.readInt() == 1;
        mSupportsSwitchingToNextInputMethod = source.readInt() == 1;
        mSupportsSwitchingToNextInputMethod = source.readInt() == 1;
        mInlineSuggestionsEnabled = source.readInt() == 1;
        mInlineSuggestionsEnabled = source.readInt() == 1;
        mSuppressesSpellChecker = source.readBoolean();
        mIsVrOnly = source.readBoolean();
        mIsVrOnly = source.readBoolean();
        mService = ResolveInfo.CREATOR.createFromParcel(source);
        mService = ResolveInfo.CREATOR.createFromParcel(source);
        mSubtypes = new InputMethodSubtypeArray(source);
        mSubtypes = new InputMethodSubtypeArray(source);
@@ -342,6 +353,7 @@ public final class InputMethodInfo implements Parcelable {
        mForceDefault = forceDefault;
        mForceDefault = forceDefault;
        mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
        mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
        mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
        mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
        mSuppressesSpellChecker = false;
        mIsVrOnly = isVrOnly;
        mIsVrOnly = isVrOnly;
    }
    }


@@ -494,7 +506,8 @@ public final class InputMethodInfo implements Parcelable {
                + " mSettingsActivityName=" + mSettingsActivityName
                + " mSettingsActivityName=" + mSettingsActivityName
                + " mIsVrOnly=" + mIsVrOnly
                + " mIsVrOnly=" + mIsVrOnly
                + " mSupportsSwitchingToNextInputMethod=" + mSupportsSwitchingToNextInputMethod
                + " mSupportsSwitchingToNextInputMethod=" + mSupportsSwitchingToNextInputMethod
                + " mInlineSuggestionsEnabled=" + mInlineSuggestionsEnabled);
                + " mInlineSuggestionsEnabled=" + mInlineSuggestionsEnabled
                + " mSuppressesSpellChecker=" + mSuppressesSpellChecker);
        pw.println(prefix + "mIsDefaultResId=0x"
        pw.println(prefix + "mIsDefaultResId=0x"
                + Integer.toHexString(mIsDefaultResId));
                + Integer.toHexString(mIsDefaultResId));
        pw.println(prefix + "Service:");
        pw.println(prefix + "Service:");
@@ -562,6 +575,13 @@ public final class InputMethodInfo implements Parcelable {
        return mInlineSuggestionsEnabled;
        return mInlineSuggestionsEnabled;
    }
    }


    /**
     * Return {@code true} if this input method suppresses spell checker.
     */
    public boolean suppressesSpellChecker() {
        return mSuppressesSpellChecker;
    }

    /**
    /**
     * Used to package this object into a {@link Parcel}.
     * Used to package this object into a {@link Parcel}.
     *
     *
@@ -576,6 +596,7 @@ public final class InputMethodInfo implements Parcelable {
        dest.writeInt(mIsAuxIme ? 1 : 0);
        dest.writeInt(mIsAuxIme ? 1 : 0);
        dest.writeInt(mSupportsSwitchingToNextInputMethod ? 1 : 0);
        dest.writeInt(mSupportsSwitchingToNextInputMethod ? 1 : 0);
        dest.writeInt(mInlineSuggestionsEnabled ? 1 : 0);
        dest.writeInt(mInlineSuggestionsEnabled ? 1 : 0);
        dest.writeBoolean(mSuppressesSpellChecker);
        dest.writeBoolean(mIsVrOnly);
        dest.writeBoolean(mIsVrOnly);
        mService.writeToParcel(dest, flags);
        mService.writeToParcel(dest, flags);
        mSubtypes.writeToParcel(dest);
        mSubtypes.writeToParcel(dest);
+20 −0
Original line number Original line Diff line number Diff line
@@ -444,6 +444,13 @@ public final class InputMethodManager {
     */
     */
    private Matrix mActivityViewToScreenMatrix = null;
    private Matrix mActivityViewToScreenMatrix = null;


    /**
     * As reported by {@link InputBindResult}. This value is determined by
     * {@link com.android.internal.R.styleable#InputMethod_suppressesSpellChecking}.
     */
    @GuardedBy("mH")
    private boolean mIsInputMethodSuppressingSpellChecker = false;

    // -----------------------------------------------------------
    // -----------------------------------------------------------


    /**
    /**
@@ -858,6 +865,8 @@ public final class InputMethodManager {
                        mCurId = res.id;
                        mCurId = res.id;
                        mBindSequence = res.sequence;
                        mBindSequence = res.sequence;
                        mActivityViewToScreenMatrix = res.getActivityViewToScreenMatrix();
                        mActivityViewToScreenMatrix = res.getActivityViewToScreenMatrix();
                        mIsInputMethodSuppressingSpellChecker =
                                res.isInputMethodSuppressingSpellChecker;
                    }
                    }
                    startInputInner(StartInputReason.BOUND_TO_IMMS, null, 0, 0, 0);
                    startInputInner(StartInputReason.BOUND_TO_IMMS, null, 0, 0, 0);
                    return;
                    return;
@@ -1469,6 +1478,15 @@ public final class InputMethodManager {
        }
        }
    }
    }


    /**
     * Return {@code true} if the input method is suppressing system spell checker.
     */
    public boolean isInputMethodSuppressingSpellChecker() {
        synchronized (mH) {
            return mIsInputMethodSuppressingSpellChecker;
        }
    }

    /**
    /**
     * Reset all of the state associated with being bound to an input method.
     * Reset all of the state associated with being bound to an input method.
     */
     */
@@ -1513,6 +1531,7 @@ public final class InputMethodManager {
    @UnsupportedAppUsage
    @UnsupportedAppUsage
    void finishInputLocked() {
    void finishInputLocked() {
        mActivityViewToScreenMatrix = null;
        mActivityViewToScreenMatrix = null;
        mIsInputMethodSuppressingSpellChecker = false;
        setNextServedViewLocked(null);
        setNextServedViewLocked(null);
        if (getServedViewLocked() != null) {
        if (getServedViewLocked() != null) {
            if (DEBUG) {
            if (DEBUG) {
@@ -2037,6 +2056,7 @@ public final class InputMethodManager {
                    return false;
                    return false;
                }
                }
                mActivityViewToScreenMatrix = res.getActivityViewToScreenMatrix();
                mActivityViewToScreenMatrix = res.getActivityViewToScreenMatrix();
                mIsInputMethodSuppressingSpellChecker = res.isInputMethodSuppressingSpellChecker;
                if (res.id != null) {
                if (res.id != null) {
                    setInputChannelLocked(res.channel);
                    setInputChannelLocked(res.channel);
                    mBindSequence = res.sequence;
                    mBindSequence = res.sequence;
+11 −0
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@ import android.os.Message;
import android.os.Process;
import android.os.Process;
import android.os.RemoteException;
import android.os.RemoteException;
import android.util.Log;
import android.util.Log;
import android.view.inputmethod.InputMethodManager;


import com.android.internal.textservice.ISpellCheckerSession;
import com.android.internal.textservice.ISpellCheckerSession;
import com.android.internal.textservice.ISpellCheckerSessionListener;
import com.android.internal.textservice.ISpellCheckerSessionListener;
@@ -176,6 +177,11 @@ public class SpellCheckerSession {
     * @param suggestionsLimit the maximum number of suggestions that will be returned
     * @param suggestionsLimit the maximum number of suggestions that will be returned
     */
     */
    public void getSentenceSuggestions(TextInfo[] textInfos, int suggestionsLimit) {
    public void getSentenceSuggestions(TextInfo[] textInfos, int suggestionsLimit) {
        final InputMethodManager imm = mTextServicesManager.getInputMethodManager();
        if (imm != null && imm.isInputMethodSuppressingSpellChecker()) {
            handleOnGetSentenceSuggestionsMultiple(new SentenceSuggestionsInfo[0]);
            return;
        }
        mSpellCheckerSessionListenerImpl.getSentenceSuggestionsMultiple(
        mSpellCheckerSessionListenerImpl.getSentenceSuggestionsMultiple(
                textInfos, suggestionsLimit);
                textInfos, suggestionsLimit);
    }
    }
@@ -204,6 +210,11 @@ public class SpellCheckerSession {
        if (DBG) {
        if (DBG) {
            Log.w(TAG, "getSuggestions from " + mSpellCheckerInfo.getId());
            Log.w(TAG, "getSuggestions from " + mSpellCheckerInfo.getId());
        }
        }
        final InputMethodManager imm = mTextServicesManager.getInputMethodManager();
        if (imm != null && imm.isInputMethodSuppressingSpellChecker()) {
            handleOnGetSuggestionsMultiple(new SuggestionsInfo[0]);
            return;
        }
        mSpellCheckerSessionListenerImpl.getSuggestionsMultiple(
        mSpellCheckerSessionListenerImpl.getSuggestionsMultiple(
                textInfos, suggestionsLimit, sequentialWords);
                textInfos, suggestionsLimit, sequentialWords);
    }
    }
+16 −3
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@ import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.UserHandle;
import android.os.UserHandle;
import android.util.Log;
import android.util.Log;
import android.view.inputmethod.InputMethodManager;
import android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener;
import android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener;


import com.android.internal.textservice.ISpellCheckerSessionListener;
import com.android.internal.textservice.ISpellCheckerSessionListener;
@@ -88,10 +89,15 @@ public final class TextServicesManager {
    @UserIdInt
    @UserIdInt
    private final int mUserId;
    private final int mUserId;


    private TextServicesManager(@UserIdInt int userId) throws ServiceNotFoundException {
    @Nullable
    private final InputMethodManager mInputMethodManager;

    private TextServicesManager(@UserIdInt int userId,
            @Nullable InputMethodManager inputMethodManager) throws ServiceNotFoundException {
        mService = ITextServicesManager.Stub.asInterface(
        mService = ITextServicesManager.Stub.asInterface(
                ServiceManager.getServiceOrThrow(Context.TEXT_SERVICES_MANAGER_SERVICE));
                ServiceManager.getServiceOrThrow(Context.TEXT_SERVICES_MANAGER_SERVICE));
        mUserId = userId;
        mUserId = userId;
        mInputMethodManager = inputMethodManager;
    }
    }


    /**
    /**
@@ -105,7 +111,8 @@ public final class TextServicesManager {
    @NonNull
    @NonNull
    public static TextServicesManager createInstance(@NonNull Context context)
    public static TextServicesManager createInstance(@NonNull Context context)
            throws ServiceNotFoundException {
            throws ServiceNotFoundException {
        return new TextServicesManager(context.getUserId());
        return new TextServicesManager(context.getUserId(), context.getSystemService(
                InputMethodManager.class));
    }
    }


    /**
    /**
@@ -118,7 +125,7 @@ public final class TextServicesManager {
        synchronized (TextServicesManager.class) {
        synchronized (TextServicesManager.class) {
            if (sInstance == null) {
            if (sInstance == null) {
                try {
                try {
                    sInstance = new TextServicesManager(UserHandle.myUserId());
                    sInstance = new TextServicesManager(UserHandle.myUserId(), null);
                } catch (ServiceNotFoundException e) {
                } catch (ServiceNotFoundException e) {
                    throw new IllegalStateException(e);
                    throw new IllegalStateException(e);
                }
                }
@@ -127,6 +134,12 @@ public final class TextServicesManager {
        }
        }
    }
    }


    /** @hide */
    @Nullable
    public InputMethodManager getInputMethodManager() {
        return mInputMethodManager;
    }

    /**
    /**
     * Returns the language component of a given locale string.
     * Returns the language component of a given locale string.
     */
     */
Loading