diff options
| -rw-r--r-- | core/java/android/inputmethodservice/InputMethodService.java | 59 | ||||
| -rw-r--r-- | core/java/android/inputmethodservice/NavigationBarController.java | 76 | 
2 files changed, 83 insertions, 52 deletions
| diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 84d96bd1e155..3d6da5452ad2 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -435,6 +435,11 @@ public class InputMethodService extends AbstractInputMethodService {      }      /** +     * Cached value of {@link #canImeRenderGesturalNavButtons}, as it doesn't change at runtime. +     */ +    private final boolean mCanImeRenderGesturalNavButtons = canImeRenderGesturalNavButtons(); + +    /**       * Allows the system to optimize the back button affordance based on the presence of software       * keyboard.       * @@ -564,6 +569,9 @@ public class InputMethodService extends AbstractInputMethodService {      private final NavigationBarController mNavigationBarController =              new NavigationBarController(this); +    /** Whether a custom IME Switcher button was requested to be visible. */ +    private boolean mCustomImeSwitcherButtonRequestedVisible; +      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)      int mTheme = 0; @@ -783,7 +791,7 @@ public class InputMethodService extends AbstractInputMethodService {              Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");              mPrivOps.set(params.privilegedOperations);              InputMethodPrivilegedOperationsRegistry.put(params.token, mPrivOps); -            mNavigationBarController.onNavButtonFlagsChanged(params.navigationBarFlags); +            onNavButtonFlagsChanged(params.navigationBarFlags);              attachToken(params.token);              Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);          } @@ -893,7 +901,7 @@ public class InputMethodService extends AbstractInputMethodService {          public final void dispatchStartInput(@Nullable InputConnection inputConnection,                  @NonNull IInputMethod.StartInputParams params) {              mPrivOps.reportStartInputAsync(params.startInputToken); -            mNavigationBarController.onNavButtonFlagsChanged(params.navigationBarFlags); +            onNavButtonFlagsChanged(params.navigationBarFlags);              if (params.restarting) {                  restartInput(inputConnection, params.editorInfo);              } else { @@ -918,6 +926,20 @@ public class InputMethodService extends AbstractInputMethodService {          @Override          public void onNavButtonFlagsChanged(@InputMethodNavButtonFlags int navButtonFlags) {              mNavigationBarController.onNavButtonFlagsChanged(navButtonFlags); +            if (!mCanImeRenderGesturalNavButtons) { +                final boolean showImeSwitcher = (navButtonFlags +                        & InputMethodNavButtonFlags.SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN) != 0; +                // The IME cannot draw the IME nav bar, so this will never be visible. In this case +                // the system nav bar hosts the IME buttons. +                // The system nav bar will be hidden when the IME is shown and the config is set. +                final boolean navBarNotVisible = getApplicationContext().getResources() +                        .getBoolean(com.android.internal.R.bool.config_hideNavBarForKeyboard); +                final boolean visible = showImeSwitcher && navBarNotVisible; +                if (visible != mCustomImeSwitcherButtonRequestedVisible) { +                    mCustomImeSwitcherButtonRequestedVisible = visible; +                    onCustomImeSwitcherButtonRequestedVisible(visible); +                } +            }          }          /** @@ -4473,28 +4495,27 @@ public class InputMethodService extends AbstractInputMethodService {      /**       * 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>When this method is called with {@code true} by the system, the IME must show a button +     * within its UI to switch IMEs. When it is called with {@code false}, it must hide this button. +     * +     * <p>Normally, the system provides a button for switching to a different IME when that is +     * appropriate. Under certain circumstances, namely when the IME successfully asks to hide the +     * system-provided navigation bar (with {@code getWindowInsetsController().hide(captionBar())}), +     * providing this button is delegated to the IME through this callback.       * -     * <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 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>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> +     * {@code false}.       *       * <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> +     * visible. However, this is not guaranteed to be called before the IME is shown, as it may +     * depend on the IME requesting to hide the system-provided 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.       *       * @param visible whether the button is requested visible or not.       */ @@ -4686,6 +4707,8 @@ public class InputMethodService extends AbstractInputMethodService {                  + " touchableRegion=" + mTmpInsets.touchableRegion);          p.println("  mSettingsObserver=" + mSettingsObserver);          p.println("  mNavigationBarController=" + mNavigationBarController.toDebugString()); +        p.println("  mCustomImeSwitcherButtonRequestedVisible=" +                + mCustomImeSwitcherButtonRequestedVisible);      }      private final ImeTracing.ServiceDumper mDumper = new ImeTracing.ServiceDumper() { diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java index 7da053d0010e..f1dee89b0b1d 100644 --- a/core/java/android/inputmethodservice/NavigationBarController.java +++ b/core/java/android/inputmethodservice/NavigationBarController.java @@ -170,6 +170,9 @@ final class NavigationBarController {          private boolean mShouldShowImeSwitcherWhenImeIsShown; +        /** Whether a custom IME Switcher button should be visible. */ +        private boolean mCustomImeSwitcherButtonRequestedVisible; +          @Appearance          private int mAppearance; @@ -181,9 +184,6 @@ 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]; @@ -275,7 +275,9 @@ final class NavigationBarController {                      // IME navigation bar.                      boolean visible = insets.isVisible(captionBar());                      mNavigationBarFrame.setVisibility(visible ? View.VISIBLE : View.GONE); -                    checkCustomImeSwitcherVisibility(); +                    checkCustomImeSwitcherButtonRequestedVisible( +                            mShouldShowImeSwitcherWhenImeIsShown, mImeDrawsImeNavBar, +                            !visible /* imeNavBarNotVisible */);                  }                  return view.onApplyWindowInsets(insets);              }); @@ -502,33 +504,31 @@ final class NavigationBarController {                      mShouldShowImeSwitcherWhenImeIsShown;              mShouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherWhenImeIsShown; -            checkCustomImeSwitcherVisibility(); -              mService.mWindow.getWindow().getDecorView().getWindowInsetsController()                      .setImeCaptionBarInsetsHeight(getImeCaptionBarHeight(imeDrawsImeNavBar));              if (imeDrawsImeNavBar) {                  installNavigationBarFrameIfNecessary(); -                if (mNavigationBarFrame == null) { -                    return; -                } -                if (mShouldShowImeSwitcherWhenImeIsShown -                        == prevShouldShowImeSwitcherWhenImeIsShown) { -                    return; -                } -                final NavigationBarView navigationBarView = mNavigationBarFrame.findViewByPredicate( -                        NavigationBarView.class::isInstance); -                if (navigationBarView != null) { -                    // TODO(b/213337792): Support InputMethodService#setBackDisposition(). -                    // TODO(b/213337792): Set NAVBAR_IME_VISIBLE only when necessary. -                    final int flags = NAVBAR_BACK_DISMISS_IME | NAVBAR_IME_VISIBLE -                            | (mShouldShowImeSwitcherWhenImeIsShown -                                    ? NAVBAR_IME_SWITCHER_BUTTON_VISIBLE : 0); -                    navigationBarView.setNavbarFlags(flags); +                if (mNavigationBarFrame != null && mShouldShowImeSwitcherWhenImeIsShown +                        != prevShouldShowImeSwitcherWhenImeIsShown) { +                    final NavigationBarView navigationBarView = mNavigationBarFrame +                            .findViewByPredicate(NavigationBarView.class::isInstance); +                    if (navigationBarView != null) { +                        // TODO(b/213337792): Support InputMethodService#setBackDisposition(). +                        // TODO(b/213337792): Set NAVBAR_IME_VISIBLE only when necessary. +                        final int flags = NAVBAR_BACK_DISMISS_IME | NAVBAR_IME_VISIBLE +                                | (mShouldShowImeSwitcherWhenImeIsShown +                                ? NAVBAR_IME_SWITCHER_BUTTON_VISIBLE : 0); +                        navigationBarView.setNavbarFlags(flags); +                    }                  }              } else {                  uninstallNavigationBarFrameIfNecessary();              } + +            // Check custom IME Switcher button visibility after (un)installing nav bar frame. +            checkCustomImeSwitcherButtonRequestedVisible(shouldShowImeSwitcherWhenImeIsShown, +                    imeDrawsImeNavBar, !isShown() /* imeNavBarNotVisible */);          }          @Override @@ -631,22 +631,29 @@ final class NavigationBarController {          }          /** -         * 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: +         * Checks if a custom IME Switcher button should be requested visible, and notifies the IME +         * when this state changes. This is only {@code true} when the IME Switcher button is +         * requested visible, and the navigation bar is not requested visible.           * -         * <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> +         * @param buttonVisible       whether the IME Switcher button is requested visible. +         * @param shouldDrawImeNavBar whether the IME navigation bar should be drawn. +         * @param imeNavBarNotVisible whether the IME navigation bar is not requested visible. This +         *                            will be {@code true} if it is requested hidden or not +         *                            installed.           */ -        private void checkCustomImeSwitcherVisibility() { +        private void checkCustomImeSwitcherButtonRequestedVisible(boolean buttonVisible, +                boolean shouldDrawImeNavBar, boolean imeNavBarNotVisible) {              if (!Flags.imeSwitcherRevampApi()) {                  return;              } -            final boolean visible = mImeDrawsImeNavBar && mShouldShowImeSwitcherWhenImeIsShown -                    && mNavigationBarFrame != null && !isShown(); -            if (visible != mCustomImeSwitcherVisible) { -                mCustomImeSwitcherVisible = visible; -                mService.onCustomImeSwitcherButtonRequestedVisible(mCustomImeSwitcherVisible); +            // The system nav bar will be hidden when the IME is shown and the config is set. +            final boolean navBarNotVisible = shouldDrawImeNavBar ? imeNavBarNotVisible +                    : mService.getResources().getBoolean( +                            com.android.internal.R.bool.config_hideNavBarForKeyboard); +            final boolean visible = buttonVisible && navBarNotVisible; +            if (visible != mCustomImeSwitcherButtonRequestedVisible) { +                mCustomImeSwitcherButtonRequestedVisible = visible; +                mService.onCustomImeSwitcherButtonRequestedVisible(visible);              }          } @@ -656,7 +663,8 @@ final class NavigationBarController {                      + " mNavigationBarFrame=" + mNavigationBarFrame                      + " mShouldShowImeSwitcherWhenImeIsShown="                      + mShouldShowImeSwitcherWhenImeIsShown -                    + " mCustomImeSwitcherVisible="  + mCustomImeSwitcherVisible +                    + " mCustomImeSwitcherButtonRequestedVisible=" +                    + mCustomImeSwitcherButtonRequestedVisible                      + " mAppearance=0x" + Integer.toHexString(mAppearance)                      + " mDarkIntensity=" + mDarkIntensity                      + " mDrawLegacyNavigationBarBackground=" + mDrawLegacyNavigationBarBackground |