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

Commit c7ca3684 authored by Yohei Yukawa's avatar Yohei Yukawa
Browse files

Stop relying on IMM in IMS for token-guarded IME APIs

This is a follow up CL to previous CLs [1][2][3] that made sure that
APIs that are exposed only to IMEs should live in InputMethodService
instead of InputMethodManager.

Now that we have a dedicated Binder inferface [4] that allows
InputMethodService (IMS) to directly send IPCs to
InputMethodManagerService (IMMS) without relying on
InputMethodManager (IMM), it is natural for the above public APIs in
IMS to stop relying on IMM.

This CL also addresses a small concern that it is no longer obvious
when those APIs become available.  Previously, it was a bit more
obvious that passing null IME token doesn't work so IME developers
could imagine that those APIs were unavailable until attachToken() is
called.

With this CL, InputMethodPrivilegedOperations starts showing warning
messages when called too early, which we hope help IME developers
understand why those APIs do nothing when called too early.

  [1]: I3163f3cbe557c85103ca287bee0874a3b4194032
       d8d03a8e
  [2]: If6a786c5774805d041ea9672ef2721e4a38df7fc
       fbc2f7ac
  [3]: I6efd5ca473e33e6faeadb7eea7772b9d2b8ca12b
       164cfba5
  [4]: I2f3ec3c5de546fb3603275a4b64000ed3f863b65
       c54c1171

Bug: 114418674
Test: atest CtsInputMethodTestCases CtsInputMethodServiceHostTestCases
Change-Id: I995c4b922f91b94438c1292392b2c3030598594f
parent 2bc3d6f0
Loading
Loading
Loading
Loading
+9 −9
Original line number Diff line number Diff line
@@ -1170,7 +1170,7 @@ public class InputMethodService extends AbstractInputMethodService {
     * used input method and subtype.
     */
    public final boolean switchToPreviousInputMethod() {
        return mImm.switchToPreviousInputMethodInternal(mToken);
        return mPrivOps.switchToPreviousInputMethod();
    }

    /**
@@ -1182,7 +1182,7 @@ public class InputMethodService extends AbstractInputMethodService {
     * input method and subtype.
     */
    public final boolean switchToNextInputMethod(boolean onlyCurrentIme) {
        return mImm.switchToNextInputMethodInternal(mToken, onlyCurrentIme);
        return mPrivOps.switchToNextInputMethod(onlyCurrentIme);
    }

    /**
@@ -1195,7 +1195,7 @@ public class InputMethodService extends AbstractInputMethodService {
     * between IMEs and subtypes.
     */
    public final boolean shouldOfferSwitchingToNextInputMethod() {
        return mImm.shouldOfferSwitchingToNextInputMethodInternal(mToken);
        return mPrivOps.shouldOfferSwitchingToNextInputMethod();
    }

    public boolean getCurrentInputStarted() {
@@ -1513,12 +1513,12 @@ public class InputMethodService extends AbstractInputMethodService {

    public void showStatusIcon(@DrawableRes int iconResId) {
        mStatusIcon = iconResId;
        mImm.showStatusIconInternal(mToken, getPackageName(), iconResId);
        mPrivOps.updateStatusIcon(getPackageName(), iconResId);
    }

    public void hideStatusIcon() {
        mStatusIcon = 0;
        mImm.hideStatusIconInternal(mToken);
        mPrivOps.updateStatusIcon(null, 0);
    }

    /**
@@ -1529,7 +1529,7 @@ public class InputMethodService extends AbstractInputMethodService {
     * @param id Unique identifier of the new input method to start.
     */
    public void switchInputMethod(String id) {
        mImm.setInputMethodInternal(mToken, id);
        mPrivOps.setInputMethod(id);
    }

    /**
@@ -1541,7 +1541,7 @@ public class InputMethodService extends AbstractInputMethodService {
     * @param subtype The new subtype of the new input method to be switched to.
     */
    public final void switchInputMethod(String id, InputMethodSubtype subtype) {
        mImm.setInputMethodAndSubtypeInternal(mToken, id, subtype);
        mPrivOps.setInputMethodAndSubtype(id, subtype);
    }

    public void setExtractView(View view) {
@@ -2132,7 +2132,7 @@ public class InputMethodService extends AbstractInputMethodService {
     * @param flags Provides additional operating flags.
     */
    public void requestHideSelf(int flags) {
        mImm.hideSoftInputFromInputMethodInternal(mToken, flags);
        mPrivOps.hideMySoftInput(flags);
    }

    /**
@@ -2144,7 +2144,7 @@ public class InputMethodService extends AbstractInputMethodService {
     * @param flags Provides additional operating flags.
     */
    public final void requestShowSelf(int flags) {
        mImm.showSoftInputFromInputMethodInternal(mToken, flags);
        mPrivOps.showMySoftInput(flags);
    }

    private boolean handleBack(boolean doIt) {
+0 −64
Original line number Diff line number Diff line
@@ -772,13 +772,6 @@ public final class InputMethodManager {
     */
    @Deprecated
    public void showStatusIcon(IBinder imeToken, String packageName, int iconId) {
        showStatusIconInternal(imeToken, packageName, iconId);
    }

    /**
     * @hide
     */
    public void showStatusIconInternal(IBinder imeToken, String packageName, int iconId) {
        try {
            mService.updateStatusIcon(imeToken, packageName, iconId);
        } catch (RemoteException e) {
@@ -793,13 +786,6 @@ public final class InputMethodManager {
     */
    @Deprecated
    public void hideStatusIcon(IBinder imeToken) {
        hideStatusIconInternal(imeToken);
    }

    /**
     * @hide
     */
    public void hideStatusIconInternal(IBinder imeToken) {
        try {
            mService.updateStatusIcon(imeToken, null, 0);
        } catch (RemoteException e) {
@@ -1845,13 +1831,6 @@ public final class InputMethodManager {
     */
    @Deprecated
    public void setInputMethod(IBinder token, String id) {
        setInputMethodInternal(token, id);
    }

    /**
     * @hide
     */
    public void setInputMethodInternal(IBinder token, String id) {
        try {
            mService.setInputMethod(token, id);
        } catch (RemoteException e) {
@@ -1874,14 +1853,6 @@ public final class InputMethodManager {
     */
    @Deprecated
    public void setInputMethodAndSubtype(IBinder token, String id, InputMethodSubtype subtype) {
        setInputMethodAndSubtypeInternal(token, id, subtype);
    }

    /**
     * @hide
     */
    public void setInputMethodAndSubtypeInternal(
            IBinder token, String id, InputMethodSubtype subtype) {
        try {
            mService.setInputMethodAndSubtype(token, id, subtype);
        } catch (RemoteException e) {
@@ -1906,13 +1877,6 @@ public final class InputMethodManager {
     */
    @Deprecated
    public void hideSoftInputFromInputMethod(IBinder token, int flags) {
        hideSoftInputFromInputMethodInternal(token, flags);
    }

    /**
     * @hide
     */
    public void hideSoftInputFromInputMethodInternal(IBinder token, int flags) {
        try {
            mService.hideMySoftInput(token, flags);
        } catch (RemoteException e) {
@@ -1938,13 +1902,6 @@ public final class InputMethodManager {
     */
    @Deprecated
    public void showSoftInputFromInputMethod(IBinder token, int flags) {
        showSoftInputFromInputMethodInternal(token, flags);
    }

    /**
     * @hide
     */
    public void showSoftInputFromInputMethodInternal(IBinder token, int flags) {
        try {
            mService.showMySoftInput(token, flags);
        } catch (RemoteException e) {
@@ -2328,13 +2285,6 @@ public final class InputMethodManager {
     */
    @Deprecated
    public boolean switchToLastInputMethod(IBinder imeToken) {
        return switchToPreviousInputMethodInternal(imeToken);
    }

    /**
     * @hide
     */
    public boolean switchToPreviousInputMethodInternal(IBinder imeToken) {
        try {
            return mService.switchToPreviousInputMethod(imeToken);
        } catch (RemoteException e) {
@@ -2357,13 +2307,6 @@ public final class InputMethodManager {
     */
    @Deprecated
    public boolean switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme) {
        return switchToNextInputMethodInternal(imeToken, onlyCurrentIme);
    }

    /**
     * @hide
     */
    public boolean switchToNextInputMethodInternal(IBinder imeToken, boolean onlyCurrentIme) {
        try {
            return mService.switchToNextInputMethod(imeToken, onlyCurrentIme);
        } catch (RemoteException e) {
@@ -2387,13 +2330,6 @@ public final class InputMethodManager {
     */
    @Deprecated
    public boolean shouldOfferSwitchingToNextInputMethod(IBinder imeToken) {
        return shouldOfferSwitchingToNextInputMethodInternal(imeToken);
    }

    /**
     * @hide
     */
    public boolean shouldOfferSwitchingToNextInputMethodInternal(IBinder imeToken) {
        try {
            return mService.shouldOfferSwitchingToNextInputMethod(imeToken);
        } catch (RemoteException e) {
+9 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.internal.inputmethod;

import android.net.Uri;
import android.view.inputmethod.InputMethodSubtype;

import com.android.internal.inputmethod.IInputContentUriToken;

@@ -30,4 +31,12 @@ interface IInputMethodPrivilegedOperations {
    void clearLastInputMethodWindowForTransition();
    IInputContentUriToken createInputContentUriToken(in Uri contentUri, in String packageName);
    void reportFullscreenMode(boolean fullscreen);
    void setInputMethod(String id);
    void setInputMethodAndSubtype(String id, in InputMethodSubtype subtype);
    void hideMySoftInput(int flags);
    void showMySoftInput(int flags);
    void updateStatusIcon(String packageName, int iconId);
    boolean switchToPreviousInputMethod();
    boolean switchToNextInputMethod(boolean onlyCurrentIme);
    boolean shouldOfferSwitchingToNextInputMethod();
}
+157 −0
Original line number Diff line number Diff line
@@ -17,11 +17,13 @@
package com.android.internal.inputmethod;

import android.annotation.AnyThread;
import android.annotation.IdRes;
import android.annotation.Nullable;
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.inputmethod.InputMethodSubtype;

import com.android.internal.annotations.GuardedBy;

@@ -189,4 +191,159 @@ public final class InputMethodPrivilegedOperations {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Calls {@link IInputMethodPrivilegedOperations#updateStatusIcon(String, int)}.
     *
     * @param packageName package name from which the status icon should be loaded
     * @param iconResId resource ID of the icon to be loaded
     */
    @AnyThread
    public void updateStatusIcon(String packageName, @IdRes int iconResId) {
        final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
        if (ops == null) {
            return;
        }
        try {
            ops.updateStatusIcon(packageName, iconResId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Calls {@link IInputMethodPrivilegedOperations#setInputMethod(String)}.
     *
     * @param id IME ID of the IME to switch to
     * @see android.view.inputmethod.InputMethodInfo#getId()
     */
    @AnyThread
    public void setInputMethod(String id) {
        final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
        if (ops == null) {
            return;
        }
        try {
            ops.setInputMethod(id);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Calls {@link IInputMethodPrivilegedOperations#setInputMethodAndSubtype(String,
     * InputMethodSubtype)}
     *
     * @param id IME ID of the IME to switch to
     * @param subtype {@link InputMethodSubtype} to switch to
     * @see android.view.inputmethod.InputMethodInfo#getId()
     */
    @AnyThread
    public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype) {
        final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
        if (ops == null) {
            return;
        }
        try {
            ops.setInputMethodAndSubtype(id, subtype);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Calls {@link IInputMethodPrivilegedOperations#hideMySoftInput(int)}
     *
     * @param flags additional operating flags
     * @see android.view.inputmethod.InputMethodManager#HIDE_IMPLICIT_ONLY
     * @see android.view.inputmethod.InputMethodManager#HIDE_NOT_ALWAYS
     */
    @AnyThread
    public void hideMySoftInput(int flags) {
        final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
        if (ops == null) {
            return;
        }
        try {
            ops.hideMySoftInput(flags);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Calls {@link IInputMethodPrivilegedOperations#showMySoftInput(int)}
     *
     * @param flags additional operating flags
     * @see android.view.inputmethod.InputMethodManager#SHOW_IMPLICIT
     * @see android.view.inputmethod.InputMethodManager#SHOW_FORCED
     */
    @AnyThread
    public void showMySoftInput(int flags) {
        final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
        if (ops == null) {
            return;
        }
        try {
            ops.showMySoftInput(flags);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Calls {@link IInputMethodPrivilegedOperations#switchToPreviousInputMethod()}
     *
     * @return {@code true} if handled
     */
    @AnyThread
    public boolean switchToPreviousInputMethod() {
        final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
        if (ops == null) {
            return false;
        }
        try {
            return ops.switchToPreviousInputMethod();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Calls {@link IInputMethodPrivilegedOperations#switchToNextInputMethod(boolean)}
     *
     * @param onlyCurrentIme {@code true} to switch to a {@link InputMethodSubtype} within the same
     *                       IME
     * @return {@code true} if handled
     */
    @AnyThread
    public boolean switchToNextInputMethod(boolean onlyCurrentIme) {
        final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
        if (ops == null) {
            return false;
        }
        try {
            return ops.switchToNextInputMethod(onlyCurrentIme);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Calls {@link IInputMethodPrivilegedOperations#shouldOfferSwitchingToNextInputMethod()}
     *
     * @return {@code true} if the IEM should offer a way to globally switch IME
     */
    @AnyThread
    public boolean shouldOfferSwitchingToNextInputMethod() {
        final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
        if (ops == null) {
            return false;
        }
        try {
            return ops.shouldOfferSwitchingToNextInputMethod();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}
+48 −0
Original line number Diff line number Diff line
@@ -5007,5 +5007,53 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        public void reportFullscreenMode(boolean fullscreen) {
            mImms.reportFullscreenMode(mToken, fullscreen);
        }

        @BinderThread
        @Override
        public void setInputMethod(String id) {
            mImms.setInputMethod(mToken, id);
        }

        @BinderThread
        @Override
        public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype) {
            mImms.setInputMethodAndSubtype(mToken, id, subtype);
        }

        @BinderThread
        @Override
        public void hideMySoftInput(int flags) {
            mImms.hideMySoftInput(mToken, flags);
        }

        @BinderThread
        @Override
        public void showMySoftInput(int flags) {
            mImms.showMySoftInput(mToken, flags);
        }

        @BinderThread
        @Override
        public void updateStatusIcon(String packageName, int iconId) {
            mImms.updateStatusIcon(mToken, packageName, iconId);
        }

        @BinderThread
        @Override
        public boolean switchToPreviousInputMethod() {
            return mImms.switchToPreviousInputMethod(mToken);
        }

        @BinderThread
        @Override
        public boolean switchToNextInputMethod(boolean onlyCurrentIme) {
            return mImms.switchToNextInputMethod(mToken, onlyCurrentIme);
        }

        @BinderThread
        @Override
        public boolean shouldOfferSwitchingToNextInputMethod() {
            return mImms.shouldOfferSwitchingToNextInputMethod(mToken);
        }
    }
}