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

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

Add API for Custom IME Switcher button visibility

This is a follow up to the IME Switcher revamp [1] and the ability to
to request hiding the IME navigation bar [2].

The visibility of the IME Switcher button is decided by the system. If
the button should be visible in the IME navigation bar, but this bar was
requested hidden by the IME itself, then it is the responsibility of the
IME to draw an equivalent Custom IME Switcher button.

This adds a new API for IMEs to be notified when the requested
visibility of a Custom IME Switcher button changes.

  [1]: I1005cb6b10682f3e91a7ed847c290fcc206b5faa
  [2]: I8793db69fb846046300d5a56b3b0060138ef4cd5

Flag: android.view.inputmethod.ime_switcher_revamp_api
Bug: 358031444
Test: atest InputMethodServiceTest#testOnCustomImeSwitcherButtonRequestedVisible_gestureNav
  InputMethodServiceTest#testOnCustomImeSwitcherButtonRequestedVisible_threeButtonNav
Change-Id: I243c8d3d76bc412c6498e255dacca31f4b28863e
parent ea6fd957
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -20946,6 +20946,7 @@ package android.inputmethodservice {
    method @Deprecated public android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
    method public android.view.View onCreateInputView();
    method protected void onCurrentInputMethodSubtypeChanged(android.view.inputmethod.InputMethodSubtype);
    method @FlaggedApi("android.view.inputmethod.ime_switcher_revamp_api") public void onCustomImeSwitcherButtonRequestedVisible(boolean);
    method public void onDisplayCompletions(android.view.inputmethod.CompletionInfo[]);
    method public boolean onEvaluateFullscreenMode();
    method @CallSuper public boolean onEvaluateInputViewShown();
+34 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECT
import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECTIONLESS_HANDWRITING_ERROR_OTHER;
import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED;
import static android.view.inputmethod.Flags.FLAG_CONNECTIONLESS_HANDWRITING;
import static android.view.inputmethod.Flags.FLAG_IME_SWITCHER_REVAMP_API;
import static android.view.inputmethod.Flags.ctrlShiftShortcut;
import static android.view.inputmethod.Flags.predictiveBackIme;

@@ -4391,6 +4392,39 @@ public class InputMethodService extends AbstractInputMethodService {
        return mNavigationBarController.isShown();
    }

    /**
     * Called when the requested visibility of a custom IME Switcher button changes.
     *
     * <p>When the system provides an IME navigation bar, it may decide to show an IME Switcher
     * button inside this bar. However, the IME can request hiding the bar provided by the system
     * with {@code getWindowInsetsController().hide(captionBar())} (the IME navigation bar provides
     * {@link Type#captionBar() captionBar} insets to the IME window). If the request is successful,
     * then it becomes the IME's responsibility to provide a custom IME Switcher button in its
     * input view, with equivalent functionality.</p>
     *
     * <p>This custom button is only requested to be visible when the system provides the IME
     * navigation bar, both the bar and the IME Switcher button inside it should be visible,
     * but the IME successfully requested to hide the bar. This does not depend on the current
     * visibility of the IME. It could be called with {@code true} while the IME is hidden, in
     * which case the IME should prepare to show the button as soon as the IME itself is shown.</p>
     *
     * <p>This is only called when the requested visibility changes. The default value is
     * {@code false} and as such, this will not be called initially if the resulting value is
     * {@code false}.</p>
     *
     * <p>This can be called at any time after {@link #onCreate}, even if the IME is not currently
     * visible. However, this is not guaranteed to be called before the IME is shown, as it depends
     * on when the IME requested hiding the IME navigation bar. If the request is sent during
     * the showing flow (e.g. during {@link #onStartInputView}), this will be called shortly after
     * {@link #onWindowShown}, but before the first IME frame is drawn.</p>
     *
     * @param visible whether the button is requested visible or not.
     */
    @FlaggedApi(FLAG_IME_SWITCHER_REVAMP_API)
    public void onCustomImeSwitcherButtonRequestedVisible(boolean visible) {
        // Intentionally empty
    }

    /**
     * Called when the IME switch button was clicked from the client. Depending on the number of
     * enabled IME subtypes, this will either switch to the next IME/subtype, or show the input
+28 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import android.view.WindowInsets;
import android.view.WindowInsetsController.Appearance;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.view.inputmethod.Flags;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;

@@ -178,6 +179,9 @@ final class NavigationBarController {

        private boolean mDrawLegacyNavigationBarBackground;

        /** Whether a custom IME Switcher button should be visible. */
        private boolean mCustomImeSwitcherVisible;

        private final Rect mTempRect = new Rect();
        private final int[] mTempPos = new int[2];

@@ -265,6 +269,7 @@ final class NavigationBarController {
                    // IME navigation bar.
                    boolean visible = insets.isVisible(captionBar());
                    mNavigationBarFrame.setVisibility(visible ? View.VISIBLE : View.GONE);
                    checkCustomImeSwitcherVisibility();
                }
                return view.onApplyWindowInsets(insets);
            });
@@ -491,6 +496,8 @@ final class NavigationBarController {
                    mShouldShowImeSwitcherWhenImeIsShown;
            mShouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherWhenImeIsShown;

            checkCustomImeSwitcherVisibility();

            mService.mWindow.getWindow().getDecorView().getWindowInsetsController()
                    .setImeCaptionBarInsetsHeight(getImeCaptionBarHeight(imeDrawsImeNavBar));

@@ -616,12 +623,33 @@ final class NavigationBarController {
                    && mNavigationBarFrame.getVisibility() == View.VISIBLE;
        }

        /**
         * Checks if a custom IME Switcher button should be visible, and notifies the IME when this
         * state changes. This can only be {@code true} if three conditions are met:
         *
         * <li>The IME should draw the IME navigation bar.</li>
         * <li>The IME Switcher button should be visible when the IME is visible.</li>
         * <li>The IME navigation bar should be visible, but was requested hidden by the IME.</li>
         */
        private void checkCustomImeSwitcherVisibility() {
            if (!Flags.imeSwitcherRevampApi()) {
                return;
            }
            final boolean visible = mImeDrawsImeNavBar && mShouldShowImeSwitcherWhenImeIsShown
                    && mNavigationBarFrame != null && !isShown();
            if (visible != mCustomImeSwitcherVisible) {
                mCustomImeSwitcherVisible = visible;
                mService.onCustomImeSwitcherButtonRequestedVisible(mCustomImeSwitcherVisible);
            }
        }

        @Override
        public String toDebugString() {
            return "{mImeDrawsImeNavBar=" + mImeDrawsImeNavBar
                    + " mNavigationBarFrame=" + mNavigationBarFrame
                    + " mShouldShowImeSwitcherWhenImeIsShown="
                    + mShouldShowImeSwitcherWhenImeIsShown
                    + " mCustomImeSwitcherVisible="  + mCustomImeSwitcherVisible
                    + " mAppearance=0x" + Integer.toHexString(mAppearance)
                    + " mDarkIntensity=" + mDarkIntensity
                    + " mDrawLegacyNavigationBarBackground=" + mDrawLegacyNavigationBarBackground