diff options
| author | 2023-11-10 16:55:23 +0100 | |
|---|---|---|
| committer | 2023-11-16 11:24:48 +0100 | |
| commit | 56beb96e7000324616857971a60df5e883bee3d1 (patch) | |
| tree | a43e5cc38f1c4c2d05f213a406499a350e773a77 | |
| parent | 02b3211ef962f80aa071c84afe69aec8d58392cf (diff) | |
Add unit tests for hiding the IME nav bar
This adds unit tests for the newly added IME captio bar insetsSource,
and for the code paths through InsetsController for showing and hiding
the IME nav bar.
Bug: 310199730
Test: atest
FrameworksImeTests:InputMethodServiceTest#testShowHideImeNavigationBar_doesDrawImeNavBar
FrameworksImeTests:InputMethodServiceTest#testShowHideImeNavigationBar_doesNotDrawImeNavBar
InsetsSourceTest#testCalculateInsets_imeCaptionBar
Change-Id: I84accc9666eef2bdeaa7073acd7f364938770b65
6 files changed, 128 insertions, 2 deletions
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java index f16e2439f3f4..e2d215ebfed4 100644 --- a/core/java/android/inputmethodservice/AbstractInputMethodService.java +++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java @@ -33,6 +33,8 @@ import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethodSession; import android.window.WindowProviderService; +import com.android.internal.annotations.VisibleForTesting; + import java.io.FileDescriptor; import java.io.PrintWriter; @@ -72,8 +74,9 @@ public abstract class AbstractInputMethodService extends WindowProviderService * {@code null} if {@link #onCreateInputMethodInterface()} is not yet called. * @hide */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) @Nullable - protected final InputMethod getInputMethodInternal() { + public final InputMethod getInputMethodInternal() { return mInputMethod; } diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index ba80811e198c..18d3e5e02fbe 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -149,6 +149,7 @@ import android.window.OnBackInvokedDispatcher; import android.window.WindowMetricsHelper; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.inputmethod.IInlineSuggestionsRequestCallback; import com.android.internal.inputmethod.IInputContentUriToken; import com.android.internal.inputmethod.IInputMethod; @@ -3997,6 +3998,16 @@ public class InputMethodService extends AbstractInputMethodService { } /** + * Returns whether the IME navigation bar is currently shown, for testing purposes. + * + * @hide + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + public final boolean isImeNavigationBarShownForTesting() { + return mNavigationBarController.isShown(); + } + + /** * Used to inject custom {@link InputMethodServiceInternal}. * * @return the {@link InputMethodServiceInternal} to be used. diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java index 8be4c5858694..9c55b0ee0623 100644 --- a/core/java/android/inputmethodservice/NavigationBarController.java +++ b/core/java/android/inputmethodservice/NavigationBarController.java @@ -77,6 +77,10 @@ final class NavigationBarController { default void onNavButtonFlagsChanged(@InputMethodNavButtonFlags int navButtonFlags) { } + default boolean isShown() { + return false; + } + default String toDebugString() { return "No-op implementation"; } @@ -117,6 +121,13 @@ final class NavigationBarController { mImpl.onNavButtonFlagsChanged(navButtonFlags); } + /** + * Returns whether the IME navigation bar is currently shown. + */ + boolean isShown() { + return mImpl.isShown(); + } + String toDebugString() { return mImpl.toDebugString(); } @@ -561,6 +572,12 @@ final class NavigationBarController { } @Override + public boolean isShown() { + return mNavigationBarFrame != null + && mNavigationBarFrame.getVisibility() == View.VISIBLE; + } + + @Override public String toDebugString() { return "{mImeDrawsImeNavBar=" + mImeDrawsImeNavBar + " mNavigationBarFrame=" + mNavigationBarFrame diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java index 1acc384b18da..cabab6c80bf5 100644 --- a/core/java/android/view/InsetsSource.java +++ b/core/java/android/view/InsetsSource.java @@ -49,8 +49,9 @@ public class InsetsSource implements Parcelable { /** The insets source ID of IME */ public static final int ID_IME = createId(null, 0, ime()); + /** The insets source ID of the IME caption bar ("fake" IME navigation bar). */ - static final int ID_IME_CAPTION_BAR = + public static final int ID_IME_CAPTION_BAR = InsetsSource.createId(null /* owner */, 1 /* index */, captionBar()); /** diff --git a/core/tests/coretests/src/android/view/InsetsSourceTest.java b/core/tests/coretests/src/android/view/InsetsSourceTest.java index 9595332afc6c..e1bcd4a0727b 100644 --- a/core/tests/coretests/src/android/view/InsetsSourceTest.java +++ b/core/tests/coretests/src/android/view/InsetsSourceTest.java @@ -16,6 +16,7 @@ package android.view; +import static android.view.InsetsSource.ID_IME_CAPTION_BAR; import static android.view.WindowInsets.Type.FIRST; import static android.view.WindowInsets.Type.LAST; import static android.view.WindowInsets.Type.SIZE; @@ -52,12 +53,15 @@ public class InsetsSourceTest { private final InsetsSource mSource = new InsetsSource(0 /* id */, navigationBars()); private final InsetsSource mImeSource = new InsetsSource(1 /* id */, ime()); + private final InsetsSource mImeCaptionSource = new InsetsSource( + ID_IME_CAPTION_BAR, captionBar()); private final InsetsSource mCaptionSource = new InsetsSource(2 /* id */, captionBar()); @Before public void setUp() { mSource.setVisible(true); mImeSource.setVisible(true); + mImeCaptionSource.setVisible(true); mCaptionSource.setVisible(true); } @@ -110,6 +114,18 @@ public class InsetsSourceTest { } @Test + public void testCalculateInsets_imeCaptionBar() { + mImeCaptionSource.setFrame(new Rect(0, 400, 500, 500)); + Insets insets = mImeCaptionSource.calculateInsets(new Rect(0, 0, 500, 500), false); + assertEquals(Insets.of(0, 0, 0, 100), insets); + + // Place caption bar at top; IME caption bar must always return bottom insets + mImeCaptionSource.setFrame(new Rect(0, 0, 500, 100)); + insets = mImeCaptionSource.calculateInsets(new Rect(0, 0, 500, 500), false); + assertEquals(Insets.of(0, 0, 0, 100), insets); + } + + @Test public void testCalculateInsets_caption_resizing() { mCaptionSource.setFrame(new Rect(0, 0, 100, 100)); Insets insets = mCaptionSource.calculateInsets(new Rect(0, 0, 200, 200), false); diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java index b63a58a96b8c..21342783b79c 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java @@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; import android.app.Instrumentation; import android.content.Context; @@ -48,6 +49,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.apps.inputmethod.simpleime.ims.InputMethodServiceWrapper; import com.android.apps.inputmethod.simpleime.testing.TestActivity; +import com.android.internal.inputmethod.InputMethodNavButtonFlags; import org.junit.After; import org.junit.Before; @@ -635,6 +637,82 @@ public class InputMethodServiceTest { .getRootWindowInsets().getInsetsIgnoringVisibility(captionBar())); } + /** + * This checks that trying to show and hide the navigation bar takes effect + * when the IME does draw the IME navigation bar. + */ + @Test + public void testShowHideImeNavigationBar_doesDrawImeNavBar() throws Exception { + boolean hasNavigationBar = WindowManagerGlobal.getWindowManagerService() + .hasNavigationBar(mInputMethodService.getDisplayId()); + assumeTrue("Must have a navigation bar", hasNavigationBar); + + setShowImeWithHardKeyboard(true /* enabled */); + + // Show IME + verifyInputViewStatusOnMainSync( + () -> { + mInputMethodService.getInputMethodInternal().onNavButtonFlagsChanged( + InputMethodNavButtonFlags.IME_DRAWS_IME_NAV_BAR + | InputMethodNavButtonFlags.SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN + ); + assertThat(mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(); + }, + true /* expected */, + true /* inputViewStarted */); + assertThat(mInputMethodService.isInputViewShown()).isTrue(); + assertThat(mInputMethodService.isImeNavigationBarShownForTesting()).isTrue(); + + // Try to hide IME nav bar + mInstrumentation.runOnMainSync(() -> mInputMethodService.getWindow().getWindow() + .getInsetsController().hide(captionBar())); + mInstrumentation.waitForIdleSync(); + assertThat(mInputMethodService.isImeNavigationBarShownForTesting()).isFalse(); + + // Try to show IME nav bar + mInstrumentation.runOnMainSync(() -> mInputMethodService.getWindow().getWindow() + .getInsetsController().show(captionBar())); + mInstrumentation.waitForIdleSync(); + assertThat(mInputMethodService.isImeNavigationBarShownForTesting()).isTrue(); + } + /** + * This checks that trying to show and hide the navigation bar has no effect + * when the IME does not draw the IME navigation bar. + * + * Note: The IME navigation bar is *never* visible in 3 button navigation mode. + */ + @Test + public void testShowHideImeNavigationBar_doesNotDrawImeNavBar() throws Exception { + boolean hasNavigationBar = WindowManagerGlobal.getWindowManagerService() + .hasNavigationBar(mInputMethodService.getDisplayId()); + assumeTrue("Must have a navigation bar", hasNavigationBar); + + setShowImeWithHardKeyboard(true /* enabled */); + + // Show IME + verifyInputViewStatusOnMainSync(() -> { + mInputMethodService.getInputMethodInternal().onNavButtonFlagsChanged( + 0 /* navButtonFlags */); + assertThat(mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(); + }, + true /* expected */, + true /* inputViewStarted */); + assertThat(mInputMethodService.isInputViewShown()).isTrue(); + assertThat(mInputMethodService.isImeNavigationBarShownForTesting()).isFalse(); + + // Try to hide IME nav bar + mInstrumentation.runOnMainSync(() -> mInputMethodService.getWindow().getWindow() + .getInsetsController().hide(captionBar())); + mInstrumentation.waitForIdleSync(); + assertThat(mInputMethodService.isImeNavigationBarShownForTesting()).isFalse(); + + // Try to show IME nav bar + mInstrumentation.runOnMainSync(() -> mInputMethodService.getWindow().getWindow() + .getInsetsController().show(captionBar())); + mInstrumentation.waitForIdleSync(); + assertThat(mInputMethodService.isImeNavigationBarShownForTesting()).isFalse(); + } + private void verifyInputViewStatus( Runnable runnable, boolean expected, boolean inputViewStarted) throws InterruptedException { |