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

Commit fed109a5 authored by Cosmin Băieș's avatar Cosmin Băieș
Browse files

Fix SHOW_IMPLICIT and SHOW_EXPLICIT handling

This fixes a bug introduced in the refactor from [1], where
SHOW_IMPLICIT and SHOW_EXPLICIT requests would not be handled correctly,
as they represent the same underlying bit flag value.

IntDefs were added to help understand which set of flags to use
based on call site. Requests originating from InputMethodManager
(and a few from InputMethodService) must utilise InputMethodManager
flags (i.e SHOW_IMPLICIT). When reaching the ImeVisibilityStateComputer,
these are translated to InputMethodService flags (i.e. SHOW_EXPLICIT).

Additonally, this documents and tests that `ImeVisibilityStateComputer`
keeps the strongest state set until a hide request (i.e. an implicit
show request just after a forced / explicit show request, without
any hide requests in between, will still have the
forced / explicit state set).

[1]: Id1115ceb951e4bb0361a32b824d966cc70b7d132

Bug: 289188559
Test: atest DefaultImeVisibilityApplierTest ImeVisibilityStateComputerTest
  com.android.inputmethodservice.InputMethodServiceTest
Change-Id: I0fde7ea4cec99e739eb4541cc206daa191661689
parent e6ac1838
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -433,7 +433,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
    @BinderThread
    @Override
    public void showSoftInput(IBinder showInputToken, @Nullable ImeTracker.Token statsToken,
            int flags, ResultReceiver resultReceiver) {
            @InputMethod.ShowFlags int flags, ResultReceiver resultReceiver) {
        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER);
        mCaller.executeOrSendMessage(mCaller.obtainMessageIOOO(DO_SHOW_SOFT_INPUT,
                flags, showInputToken, resultReceiver, statsToken));
+19 −24
Original line number Diff line number Diff line
@@ -607,6 +607,7 @@ public class InputMethodService extends AbstractInputMethodService {
    InputConnection mStartedInputConnection;
    EditorInfo mInputEditorInfo;

    @InputMethod.ShowFlags
    int mShowInputFlags;
    boolean mShowInputRequested;
    boolean mLastShowInputRequested;
@@ -931,8 +932,9 @@ public class InputMethodService extends AbstractInputMethodService {
         */
        @MainThread
        @Override
        public void showSoftInputWithToken(int flags, ResultReceiver resultReceiver,
                IBinder showInputToken, @Nullable ImeTracker.Token statsToken) {
        public void showSoftInputWithToken(@InputMethod.ShowFlags int flags,
                ResultReceiver resultReceiver, IBinder showInputToken,
                @Nullable ImeTracker.Token statsToken) {
            mSystemCallingShowSoftInput = true;
            mCurShowInputToken = showInputToken;
            mCurStatsToken = statsToken;
@@ -950,7 +952,7 @@ public class InputMethodService extends AbstractInputMethodService {
         */
        @MainThread
        @Override
        public void showSoftInput(int flags, ResultReceiver resultReceiver) {
        public void showSoftInput(@InputMethod.ShowFlags int flags, ResultReceiver resultReceiver) {
            ImeTracker.forLogging().onProgress(
                    mCurStatsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT);
            if (DEBUG) Log.v(TAG, "showSoftInput()");
@@ -1321,7 +1323,8 @@ public class InputMethodService extends AbstractInputMethodService {
         * InputMethodService#requestShowSelf} or {@link InputMethodService#requestHideSelf}
         */
        @Deprecated
        public void toggleSoftInput(int showFlags, int hideFlags) {
        public void toggleSoftInput(@InputMethodManager.ShowFlags int showFlags,
                @InputMethodManager.HideFlags int hideFlags) {
            InputMethodService.this.onToggleSoftInput(showFlags, hideFlags);
        }

@@ -2794,13 +2797,11 @@ public class InputMethodService extends AbstractInputMethodService {
     * and the current configuration to decide whether the input view should
     * be shown at this point.
     *
     * @param flags Provides additional information about the show request,
     * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
     * @param configChange This is true if we are re-showing due to a
     * configuration change.
     * @return Returns true to indicate that the window should be shown.
     */
    public boolean onShowInputRequested(int flags, boolean configChange) {
    public boolean onShowInputRequested(@InputMethod.ShowFlags int flags, boolean configChange) {
        if (!onEvaluateInputViewShown()) {
            return false;
        }
@@ -2830,14 +2831,14 @@ public class InputMethodService extends AbstractInputMethodService {
     * exposed to IME authors as an overridable public method without {@code @CallSuper}, we have
     * to have this method to ensure that those internal states are always updated no matter how
     * {@link #onShowInputRequested(int, boolean)} is overridden by the IME author.
     * @param flags Provides additional information about the show request,
     * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
     *
     * @param configChange This is true if we are re-showing due to a
     * configuration change.
     * @return Returns true to indicate that the window should be shown.
     * @see #onShowInputRequested(int, boolean)
     */
    private boolean dispatchOnShowInputRequested(int flags, boolean configChange) {
    private boolean dispatchOnShowInputRequested(@InputMethod.ShowFlags int flags,
            boolean configChange) {
        final boolean result = onShowInputRequested(flags, configChange);
        mInlineSuggestionSessionController.notifyOnShowInputRequested(result);
        if (result) {
@@ -3270,16 +3271,13 @@ public class InputMethodService extends AbstractInputMethodService {
     *
     * The input method will continue running, but the user can no longer use it to generate input
     * by touching the screen.
     *
     * @see InputMethodManager#HIDE_IMPLICIT_ONLY
     * @see InputMethodManager#HIDE_NOT_ALWAYS
     * @param flags Provides additional operating flags.
     */
    public void requestHideSelf(int flags) {
    public void requestHideSelf(@InputMethodManager.HideFlags int flags) {
        requestHideSelf(flags, SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_IME);
    }

    private void requestHideSelf(int flags, @SoftInputShowHideReason int reason) {
    private void requestHideSelf(@InputMethodManager.HideFlags int flags,
            @SoftInputShowHideReason int reason) {
        ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", mDumper,
                null /* icProto */);
        mPrivOps.hideMySoftInput(flags, reason);
@@ -3288,12 +3286,8 @@ public class InputMethodService extends AbstractInputMethodService {
    /**
     * Show the input method's soft input area, so the user sees the input method window and can
     * interact with it.
     *
     * @see InputMethodManager#SHOW_IMPLICIT
     * @see InputMethodManager#SHOW_FORCED
     * @param flags Provides additional operating flags.
     */
    public final void requestShowSelf(int flags) {
    public final void requestShowSelf(@InputMethodManager.ShowFlags int flags) {
        ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", mDumper,
                null /* icProto */);
        mPrivOps.showMySoftInput(flags);
@@ -3453,7 +3447,8 @@ public class InputMethodService extends AbstractInputMethodService {
    /**
     * Handle a request by the system to toggle the soft input area.
     */
    private void onToggleSoftInput(int showFlags, int hideFlags) {
    private void onToggleSoftInput(@InputMethodManager.ShowFlags int showFlags,
            @InputMethodManager.HideFlags int hideFlags) {
        if (DEBUG) Log.v(TAG, "toggleSoftInput()");
        if (isInputViewShown()) {
            requestHideSelf(
+3 −3
Original line number Diff line number Diff line
@@ -295,8 +295,8 @@ final class IInputMethodManagerGlobalInvoker {

    @AnyThread
    static boolean showSoftInput(@NonNull IInputMethodClient client, @Nullable IBinder windowToken,
            @Nullable ImeTracker.Token statsToken, int flags, int lastClickToolType,
            @Nullable ResultReceiver resultReceiver,
            @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
            int lastClickToolType, @Nullable ResultReceiver resultReceiver,
            @SoftInputShowHideReason int reason) {
        final IInputMethodManager service = getService();
        if (service == null) {
@@ -312,7 +312,7 @@ final class IInputMethodManagerGlobalInvoker {

    @AnyThread
    static boolean hideSoftInput(@NonNull IInputMethodClient client, @Nullable IBinder windowToken,
            @Nullable ImeTracker.Token statsToken, int flags,
            @Nullable ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
            @Nullable ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
        final IInputMethodManager service = getService();
        if (service == null) {
+17 −8
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.view.inputmethod;

import android.annotation.DurationMillisLong;
import android.annotation.IntDef;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -36,6 +37,8 @@ import com.android.internal.inputmethod.IInputMethod;
import com.android.internal.inputmethod.InlineSuggestionsRequestInfo;
import com.android.internal.inputmethod.InputMethodNavButtonFlags;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;

/**
@@ -270,6 +273,14 @@ public interface InputMethod {
    @MainThread
    public void revokeSession(InputMethodSession session);

    /** @hide */
    @IntDef(flag = true, prefix = { "SHOW_" }, value = {
            SHOW_EXPLICIT,
            SHOW_FORCED,
    })
    @Retention(RetentionPolicy.SOURCE)
    @interface ShowFlags {}
    
    /**
     * Flag for {@link #showSoftInput}: this show has been explicitly
     * requested by the user.  If not set, the system has decided it may be
@@ -288,8 +299,6 @@ public interface InputMethod {
    /**
     * Request that any soft input part of the input method be shown to the user.
     *
     * @param flags Provides additional information about the show request.
     * Currently may be 0 or have the bit {@link #SHOW_EXPLICIT} set.
     * @param resultReceiver The client requesting the show may wish to
     * be told the impact of their request, which should be supplied here.
     * The result code should be
@@ -304,7 +313,7 @@ public interface InputMethod {
     * @hide
     */
    @MainThread
    public default void showSoftInputWithToken(int flags, ResultReceiver resultReceiver,
    public default void showSoftInputWithToken(@ShowFlags int flags, ResultReceiver resultReceiver,
            IBinder showInputToken, @Nullable ImeTracker.Token statsToken) {
        showSoftInput(flags, resultReceiver);
    }
@@ -312,8 +321,6 @@ public interface InputMethod {
    /**
     * Request that any soft input part of the input method be shown to the user.
     * 
     * @param flags Provides additional information about the show request.
     * Currently may be 0 or have the bit {@link #SHOW_EXPLICIT} set.
     * @param resultReceiver The client requesting the show may wish to
     * be told the impact of their request, which should be supplied here.
     * The result code should be
@@ -323,11 +330,12 @@ public interface InputMethod {
     * {@link InputMethodManager#RESULT_HIDDEN InputMethodManager.RESULT_HIDDEN}.
     */
    @MainThread
    public void showSoftInput(int flags, ResultReceiver resultReceiver);
    public void showSoftInput(@ShowFlags int flags, ResultReceiver resultReceiver);

    /**
     * Request that any soft input part of the input method be hidden from the user.
     * @param flags Provides additional information about the show request.
     *
     * @param flags Provides additional information about the hide request.
     * Currently always 0.
     * @param resultReceiver The client requesting the show may wish to
     * be told the impact of their request, which should be supplied here.
@@ -350,7 +358,8 @@ public interface InputMethod {

    /**
     * Request that any soft input part of the input method be hidden from the user.
     * @param flags Provides additional information about the show request.
     *
     * @param flags Provides additional information about the hide request.
     * Currently always 0.
     * @param resultReceiver The client requesting the show may wish to
     * be told the impact of their request, which should be supplied here.
+33 −38
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import android.Manifest;
import android.annotation.DisplayContext;
import android.annotation.DrawableRes;
import android.annotation.DurationMillisLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresFeature;
@@ -121,6 +122,8 @@ import com.android.internal.view.IInputMethodManager;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collections;
@@ -2004,6 +2007,14 @@ public final class InputMethodManager {
        }
    }

    /** @hide */
    @IntDef(flag = true, prefix = { "SHOW_" }, value = {
            SHOW_IMPLICIT,
            SHOW_FORCED,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ShowFlags {}

    /**
     * Flag for {@link #showSoftInput} to indicate that this is an implicit
     * request to show the input window, not as the result of a direct request
@@ -2035,10 +2046,8 @@ public final class InputMethodManager {
     *             {@link View#isFocused view focus}, and its containing window has
     *             {@link View#hasWindowFocus window focus}. Otherwise the call fails and
     *             returns {@code false}.
     * @param flags Provides additional operating flags.  Currently may be
     * 0 or have the {@link #SHOW_IMPLICIT} bit set.
     */
    public boolean showSoftInput(View view, int flags) {
    public boolean showSoftInput(View view, @ShowFlags int flags) {
        // Re-dispatch if there is a context mismatch.
        final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
        if (fallbackImm != null) {
@@ -2101,21 +2110,20 @@ public final class InputMethodManager {
     *             {@link View#isFocused view focus}, and its containing window has
     *             {@link View#hasWindowFocus window focus}. Otherwise the call fails and
     *             returns {@code false}.
     * @param flags Provides additional operating flags.  Currently may be
     * 0 or have the {@link #SHOW_IMPLICIT} bit set.
     * @param resultReceiver If non-null, this will be called by the IME when
     * it has processed your request to tell you what it has done.  The result
     * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
     * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
     * {@link #RESULT_HIDDEN}.
     */
    public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
    public boolean showSoftInput(View view, @ShowFlags int flags, ResultReceiver resultReceiver) {
        return showSoftInput(view, null /* statsToken */, flags, resultReceiver,
                SoftInputShowHideReason.SHOW_SOFT_INPUT);
    }

    private boolean showSoftInput(View view, @Nullable ImeTracker.Token statsToken, int flags,
            ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
    private boolean showSoftInput(View view, @Nullable ImeTracker.Token statsToken,
            @ShowFlags int flags, ResultReceiver resultReceiver,
            @SoftInputShowHideReason int reason) {
        if (statsToken == null) {
            statsToken = ImeTracker.forLogging().onRequestShow(null /* component */,
                    Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT, reason);
@@ -2169,7 +2177,7 @@ public final class InputMethodManager {
     */
    @Deprecated
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768499)
    public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) {
    public void showSoftInputUnchecked(@ShowFlags int flags, ResultReceiver resultReceiver) {
        synchronized (mH) {
            final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestShow(
                    null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
@@ -2200,6 +2208,14 @@ public final class InputMethodManager {
        }
    }

    /** @hide */
    @IntDef(flag = true, prefix = { "HIDE_" }, value = {
            HIDE_IMPLICIT_ONLY,
            HIDE_NOT_ALWAYS,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface HideFlags {}

    /**
     * Flag for {@link #hideSoftInputFromWindow} and {@link InputMethodService#requestHideSelf(int)}
     * to indicate that the soft input window should only be hidden if it was not explicitly shown
@@ -2221,10 +2237,8 @@ public final class InputMethodManager {
     *
     * @param windowToken The token of the window that is making the request,
     * as returned by {@link View#getWindowToken() View.getWindowToken()}.
     * @param flags Provides additional operating flags.  Currently may be
     * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
     */
    public boolean hideSoftInputFromWindow(IBinder windowToken, int flags) {
    public boolean hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags) {
        return hideSoftInputFromWindow(windowToken, flags, null);
    }

@@ -2246,21 +2260,19 @@ public final class InputMethodManager {
     *
     * @param windowToken The token of the window that is making the request,
     * as returned by {@link View#getWindowToken() View.getWindowToken()}.
     * @param flags Provides additional operating flags.  Currently may be
     * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
     * @param resultReceiver If non-null, this will be called by the IME when
     * it has processed your request to tell you what it has done.  The result
     * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
     * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
     * {@link #RESULT_HIDDEN}.
     */
    public boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
    public boolean hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags,
            ResultReceiver resultReceiver) {
        return hideSoftInputFromWindow(windowToken, flags, resultReceiver,
                SoftInputShowHideReason.HIDE_SOFT_INPUT);
    }

    private boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
    private boolean hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags,
            ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
        final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
                null /* component */, Process.myUid(),
@@ -2463,12 +2475,6 @@ public final class InputMethodManager {
     * If not the input window will be displayed.
     * @param windowToken The token of the window that is making the request,
     * as returned by {@link View#getWindowToken() View.getWindowToken()}.
     * @param showFlags Provides additional operating flags.  May be
     * 0 or have the {@link #SHOW_IMPLICIT},
     * {@link #SHOW_FORCED} bit set.
     * @param hideFlags Provides additional operating flags.  May be
     * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
     * {@link #HIDE_NOT_ALWAYS} bit set.
     *
     * @deprecated Use {@link #showSoftInput(View, int)} or
     * {@link #hideSoftInputFromWindow(IBinder, int)} explicitly instead.
@@ -2477,7 +2483,8 @@ public final class InputMethodManager {
     * has an effect if the calling app is the current IME focus.
     */
    @Deprecated
    public void toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags) {
    public void toggleSoftInputFromWindow(IBinder windowToken, @ShowFlags int showFlags,
            @HideFlags int hideFlags) {
        ImeTracing.getInstance().triggerClientDump(
                "InputMethodManager#toggleSoftInputFromWindow", InputMethodManager.this,
                null /* icProto */);
@@ -2495,12 +2502,6 @@ public final class InputMethodManager {
     *
     * If the input window is already displayed, it gets hidden.
     * If not the input window will be displayed.
     * @param showFlags Provides additional operating flags.  May be
     * 0 or have the {@link #SHOW_IMPLICIT},
     * {@link #SHOW_FORCED} bit set.
     * @param hideFlags Provides additional operating flags.  May be
     * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
     * {@link #HIDE_NOT_ALWAYS} bit set.
     *
     * @deprecated Use {@link #showSoftInput(View, int)} or
     * {@link #hideSoftInputFromWindow(IBinder, int)} explicitly instead.
@@ -2509,7 +2510,7 @@ public final class InputMethodManager {
     * has an effect if the calling app is the current IME focus.
     */
    @Deprecated
    public void toggleSoftInput(int showFlags, int hideFlags) {
    public void toggleSoftInput(@ShowFlags int showFlags, @HideFlags int hideFlags) {
        ImeTracing.getInstance().triggerClientDump(
                "InputMethodManager#toggleSoftInput", InputMethodManager.this,
                null /* icProto */);
@@ -3522,15 +3523,12 @@ public final class InputMethodManager {
     * @param token Supplies the identifying token given to an input method
     * when it was started, which allows it to perform this operation on
     * itself.
     * @param flags Provides additional operating flags.  Currently may be
     * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
     * {@link #HIDE_NOT_ALWAYS} bit set.
     * @deprecated Use {@link InputMethodService#requestHideSelf(int)} instead. This method was
     * intended for IME developers who should be accessing APIs through the service. APIs in this
     * class are intended for app developers interacting with the IME.
     */
    @Deprecated
    public void hideSoftInputFromInputMethod(IBinder token, int flags) {
    public void hideSoftInputFromInputMethod(IBinder token, @HideFlags int flags) {
        InputMethodPrivilegedOperationsRegistry.get(token).hideMySoftInput(
                flags, SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION);
    }
@@ -3544,15 +3542,12 @@ public final class InputMethodManager {
     * @param token Supplies the identifying token given to an input method
     * when it was started, which allows it to perform this operation on
     * itself.
     * @param flags Provides additional operating flags.  Currently may be
     * 0 or have the {@link #SHOW_IMPLICIT} or
     * {@link #SHOW_FORCED} bit set.
     * @deprecated Use {@link InputMethodService#requestShowSelf(int)} instead. This method was
     * intended for IME developers who should be accessing APIs through the service. APIs in this
     * class are intended for app developers interacting with the IME.
     */
    @Deprecated
    public void showSoftInputFromInputMethod(IBinder token, int flags) {
    public void showSoftInputFromInputMethod(IBinder token, @ShowFlags int flags) {
        InputMethodPrivilegedOperationsRegistry.get(token).showMySoftInput(flags);
    }

Loading