diff options
| author | 2025-03-11 19:00:19 +0100 | |
|---|---|---|
| committer | 2025-03-19 11:07:40 +0100 | |
| commit | 3a0f01da45e46545d81556c53bfacab4aba9c780 (patch) | |
| tree | d98fb7c89e1ef543eeba7b84b98a740938fd334d | |
| parent | 663723d70d38ea7893e066820b44738b29cfea5e (diff) | |
Check system nav bar for custom IME Switcher vis
This enhances the onCustomImeSwitcherButtonRequestedVisible API to also
take into account the system navigation bar, in addition to the IME
navigation bar. The system bar is generally automatically shown whenever
the IME is shown, but this can be overriden through a config. Moreover,
the IME navigation bar can be disabled through a sysprop.
This takes into account both the config and the sysprop to provide a
more accurate response about the custom button requested visibility.
Flag: android.view.inputmethod.ime_switcher_revamp_api
Bug: 385018555
Test: atest
InputMethodServiceTest#testOnCustomImeSwitcherButtonRequestedVisible_gestureNav
InputMethodServiceTest#testOnCustomImeSwitcherButtonRequestedVisible_threeButtonNav
InputMethodServiceTest#testOnCustomImeSwitcherButtonRequestedVisible_hideNavBarForKeyboard
InputMethodServiceTest#testOnCustomImeSwitcherButtonRequestedVisible_imeNavigationBarDisabled
InputMethodServiceTest#testOnCustomImeSwitcherButtonRequestedVisible_imeNavigationBarDisabled_hideNavBarForKeyboard
Change-Id: I1746e1f4cceb118140747c7ffb2b4266e3fee31e
| -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 |